#include "zucmodule_stat.h"
#include "zucmodule_exceptions.h"
#include "nml_intf/zuc_nml.hh"
#include "zucmodule_multirobot_stat.h"

// 定义类析构函数
static void Stat_dealloc(PyStatChannel* self)
{
    // 减少 B 对象的引用计数
    Py_XDECREF(self->robstat[0]);
    Py_XDECREF(self->robstat[1]);

    delete self->c;
    PyObject_Del(self);
}

static bool check_stat(RCS_STAT_CHANNEL* zucStatusBuffer)
{
    if (!zucStatusBuffer->valid())
    {
        PyErr_Format(Exception_GetBaseError(), "zucStatusBuffer invalid err=%d", zucStatusBuffer->error_type);
        return false;
    }
    return true;
}

static PyObject* poll(PyStatChannel* s, PyObject* o)
{
    if (!check_stat(s->c))
        return NULL;

    if (s->c->peek() == ZUC_STAT_TYPE)
    {
        ZUC_STAT* zucStatus = static_cast<ZUC_STAT*>(s->c->get_address());
        memcpy(&s->status, zucStatus, sizeof(ZUC_STAT));
    }

    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject* robot_joint_val(const RobJointVal& p)
{
    PyObject* res = PyTuple_New(MAX_AXIS);
    for (size_t i = 0; i < MAX_AXIS; i++) { PyTuple_SET_ITEM(res, i, PyFloat_FromDouble(p.val[i])); }
    return res;
}

static PyObject* pose(const ZucPose& p)
{
    PyObject* res = PyTuple_New(CART_DIM);
    PyTuple_SET_ITEM(res, 0, PyFloat_FromDouble(p.tran.x));
    PyTuple_SET_ITEM(res, 1, PyFloat_FromDouble(p.tran.y));
    PyTuple_SET_ITEM(res, 2, PyFloat_FromDouble(p.tran.z));
    PyTuple_SET_ITEM(res, 3, PyFloat_FromDouble(p.a));
    PyTuple_SET_ITEM(res, 4, PyFloat_FromDouble(p.b));
    PyTuple_SET_ITEM(res, 5, PyFloat_FromDouble(p.c));
    return res;
}

#define MAX_ROBOT_NUM 2

static PyObject* Stat_robot_joint_position(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(MAX_ROBOT_NUM);
    for (int rob = 0; rob < MAX_ROBOT_NUM; rob++)
    {
        PyObject* rob_s = PyTuple_New(MAX_AXIS);
        for (size_t i = 0; i < MAX_AXIS; i++) { PyTuple_SetItem(rob_s, i, PyFloat_FromDouble(s->status.ext_motion[rob].joint[i].output)); }
        PyTuple_SetItem(res, rob, rob_s);
    }
    return res;
}

static PyObject* Stat_robot_joint_torque(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(MAX_ROBOT_NUM);
    for (int rob = 0; rob < MAX_ROBOT_NUM; rob++)
    {
        PyObject* rob_s = PyTuple_New(MAX_AXIS);
        for (size_t i = 0; i < MAX_AXIS; i++) { PyTuple_SetItem(rob_s, i, PyFloat_FromDouble(s->status.ext_motion[rob].joint[i].cmd_tor)); }
        PyTuple_SetItem(res, rob, rob_s);
    }
    return res;
}

static PyObject* Stat_robot_joint_actual_position(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(MAX_ROBOT_NUM);
    for (int rob = 0; rob < MAX_ROBOT_NUM; rob++)
    {
        PyObject* rob_s = PyTuple_New(MAX_AXIS);
        for (size_t i = 0; i < MAX_AXIS; i++) { PyTuple_SetItem(rob_s, i, PyFloat_FromDouble(s->status.ext_motion[rob].joint[i].input)); }
        PyTuple_SetItem(res, rob, rob_s);
    }
    return res;
}

static PyObject* Stat_robot_tcp_position(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(MAX_ROBOT_NUM);
    for (int rob = 0; rob < MAX_ROBOT_NUM; rob++)
    {
        PyObject* rob_s = pose(s->status.ext_motion[rob].traj.position);
        PyTuple_SetItem(res, rob, rob_s);
    }
    return res;
}

static PyObject* Stat_robot_dh_param(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(MAX_ROBOT_NUM);
    for (int rob = 0; rob < MAX_ROBOT_NUM; rob++)
    {
        PyObject* rob_s = PyTuple_New(4);
        PyTuple_SetItem(rob_s, 0, robot_joint_val(s->status.ext_motion[rob].dhParam.alpha));
        PyTuple_SetItem(rob_s, 1, robot_joint_val(s->status.ext_motion[rob].dhParam.a));
        PyTuple_SetItem(rob_s, 2, robot_joint_val(s->status.ext_motion[rob].dhParam.d));
        PyTuple_SetItem(rob_s, 3, robot_joint_val(s->status.ext_motion[rob].dhParam.joint_homeoff));
        PyTuple_SetItem(res, rob, rob_s);
    }
    return res;
}

static PyObject* Stat_robot_payload(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(MAX_ROBOT_NUM);
    for (int rob = 0; rob < MAX_ROBOT_NUM; rob++)
    {
        PyObject* rob_s = PyTuple_New(2);
        PyTuple_SetItem(rob_s, 0, PyFloat_FromDouble(s->status.ext_motion[rob].payload[0]));
        PyObject* com = PyTuple_New(3);
        for (int i = 0; i < 3; i++) { PyTuple_SetItem(com, i, PyFloat_FromDouble(s->status.ext_motion[rob].payload[i + 1])); }
        PyTuple_SetItem(rob_s, 1, com);
        PyTuple_SetItem(res, rob, rob_s);
    }
    return res;
}

static PyObject* get_io_num(PyStatChannel* s, PyObject* o)
{
    int ioType;

    if (!PyArg_ParseTuple(o, "i", &ioType))
        return NULL;

    static int dinNum = 0;
    static int doutNum = 0;
    static int ainNum = 0;
    static int aoutNum = 0;

    // extio_stat [[di], [do], [ai], [ao]]
    __attribute__((unused)) int totalDINum = 0;
    __attribute__((unused)) int totalDONum = 0;
    __attribute__((unused)) int totalAINum = 0;
    __attribute__((unused)) int totalAONum = 0;

    int arr[8], cnt = 0;
    int tio_version = 0;
    dinNum = ZUCMOT_ZLAN_DIO_NUM;
    doutNum = ZUCMOT_ZLAN_DIO_NUM;
    ainNum = ZUCMOT_ZLAN_AI_NUM;
    aoutNum = ZUCMOT_ZLAN_AO_NUM;
    if (s->status.cab_type == 2)
    {
        dinNum = ZUCMOT_SCB_USER_DIO_NUM;
        doutNum = ZUCMOT_SCB_USER_DIO_NUM;
        ainNum = ZUCMOT_SCB_USER_AIO_NUM;
        aoutNum = ZUCMOT_SCB_USER_AIO_NUM;
    }
    else if (s->status.cab_type == 3)
    {
        dinNum = ZUCMOT_MINI_USER_DIO_NUM;
        doutNum = ZUCMOT_MINI_USER_DIO_NUM;
        ainNum = ZUCMOT_MINI_USER_AIO_NUM;
        aoutNum = ZUCMOT_MINI_USER_AIO_NUM;
    }

    if (ioType == 1)
    {
        tio_version = s->status.tio[0].tioStatus.tio_version >> 8 & 0xff;
        switch (tio_version)
        {
        case 1:
            dinNum = 4;
            doutNum = 2;
            ainNum = 1;
            break;
        case 2:
            dinNum = 2;
            doutNum = 2;
            ainNum = 1;
            break;
        case 3:
            dinNum = 2;
            doutNum = 2;
            ainNum = 2;
            break;
        default:
            //默认采用tiov3的数据
            dinNum = 2;
            doutNum = 2;
            ainNum = 2;
            break;
        }
    }

    // io type: -1--> all io types, 0-->cabinet, 1-->tio; 2-->extio, 3-->delay io, 4-->modbus slave IO, 5-->profinet IO, 6-->Ethernet/IP IO
    switch (ioType)
    {
    case 0:  // cabinet io
        arr[0] = dinNum;
        arr[1] = doutNum;
        arr[2] = ainNum;
        arr[3] = aoutNum;
        cnt = 4;
        break;
    case 1:  // Tool io
        arr[0] = dinNum;
        arr[1] = doutNum;
        arr[2] = ainNum;
        cnt = 3;
        break;
    case 4:  // modbus slave
        arr[0] = ZUCMOT_MAX_MODBUS_DIO;
        arr[1] = ZUCMOT_MAX_MODBUS_DIO;
        arr[2] = ZUCMOT_UINT16_AIO_NUM;
        arr[3] = ZUCMOT_INT16_AIO_NUM;
        arr[4] = ZUCMOT_FLOAT32_AIO_NUM;
        arr[5] = ZUCMOT_UINT16_AIO_NUM;
        arr[6] = ZUCMOT_INT16_AIO_NUM;
        arr[7] = ZUCMOT_FLOAT32_AIO_NUM;
        cnt = 8;
        break;
    case 5:  // profinet io
        arr[0] = ZUCMOT_MAX_PNDev_DIO;
        arr[1] = ZUCMOT_MAX_PNDev_DIO;
        arr[2] = ZUCMOT_PNDev_INT_AIO_NUM;
        arr[3] = ZUCMOT_PNDev_FLOAT_AIO_NUM;
        arr[4] = ZUCMOT_PNDev_INT_AIO_NUM;
        arr[5] = ZUCMOT_PNDev_FLOAT_AIO_NUM;
        cnt = 6;
        break;
    case 6:  // ethernet/ip io
        if (s->status.io.eip_mode)
        {
            arr[0] = s->status.io.eip_di_num;
            arr[1] = s->status.io.eip_do_num;
            arr[2] = s->status.io.eip_ai_int_num;
            arr[3] = s->status.io.eip_ai_float_num;
            arr[4] = s->status.io.eip_ao_int_num;
            arr[5] = s->status.io.eip_ao_float_num;
        }
        else
        {
            arr[0] = ZUCMOT_MAX_EIP_DIO;
            arr[1] = ZUCMOT_MAX_EIP_DIO;
            arr[2] = ZUCMOT_EIP_INT_AIO_NUM;
            arr[3] = ZUCMOT_EIP_FLOAT_AIO_NUM;
            arr[4] = ZUCMOT_EIP_INT_AIO_NUM;
            arr[5] = ZUCMOT_EIP_FLOAT_AIO_NUM;
        }

        cnt = 6;
        break;
    default:
        arr[0] = -1;
        arr[1] = -1;
        arr[2] = -1;
        arr[3] = -1;
        cnt = 4;
        break;
    }
    return int_array(arr, cnt);
}

static PyObject* robot(PyStatChannel* s, PyObject* o)
{
    int robindex = 0;

    if (!PyArg_ParseTuple(o, "i", &robindex))
        return NULL;
    if (robindex >= MAX_ROBOT_NUM)
    {
        PyErr_Format(Exception_GetBaseError(), "robot index out of range");
        return NULL;
    }
    Py_INCREF(s->robstat[robindex]);
    return s->robstat[robindex];
}
// 定义类方法
static PyMethodDef Stat_methods[] = {{"poll", (PyCFunction)poll, METH_NOARGS, "Update current machine state"},
                                     {"get_io_num", (PyCFunction)get_io_num, METH_VARARGS, "get io num"},
                                     {"robot", (PyCFunction)robot, METH_VARARGS, "get robot object"},
                                     {NULL}};

// getter / setter 函数定义
// 复杂的get函数需要手动定义
static PyObject* Stat_axes(PyStatChannel* s)
{
    PyErr_WarnEx(PyExc_DeprecationWarning, "stat.axes is deprecated and will be removed in the future", 0);
    return PyLong_FromLong(s->status.motion.traj.deprecated_axes);
}

static PyObject* int_eip_array(unsigned char* arr, int sz)
{
    PyObject* res = PyTuple_New(sz);
    int val = 0;
    int k = 0;
    for (int i = 0; i < (sz / 8); ++i)  // DI和DO数量必须为8的n次方。
    {
        for (int j = 0; j < 8; ++j)
        {
            val = 0x01 & (0xff & (arr[i] >> j));
            PyTuple_SET_ITEM(res, k++, PyLong_FromLong(val));
        }
    }
    return res;
}

static PyObject* double_eip_array(unsigned char* arr, int aio_int, int sz)
{
    PyObject* res = PyTuple_New(sz);
    int k = 0;
    union UN_Float un_float;
    union UN_INT32 un_int32;
    for (int i = 0; i < sz * 4; i = i + 4)
    {
        if (i < aio_int * 4)
        {
            un_int32.PN_UI8[0] = arr[i + 0];
            un_int32.PN_UI8[1] = arr[i + 1];
            un_int32.PN_UI8[2] = arr[i + 2];
            un_int32.PN_UI8[3] = arr[i + 3];
            PyTuple_SET_ITEM(res, k++, PyFloat_FromDouble(un_int32.PN_IN32));
        }
        else
        {
            un_float.PN_UI8[0] = arr[i + 0];
            un_float.PN_UI8[1] = arr[i + 1];
            un_float.PN_UI8[2] = arr[i + 2];
            un_float.PN_UI8[3] = arr[i + 3];
            PyTuple_SET_ITEM(res, k++, PyFloat_FromDouble(un_float.PN_FLT));
        }
    }
    return res;
}

static PyObject* Stat_onekey_upgrade_verion(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(4);
    // for(int i = 0;i<4;i++)
    // {
    //     PyTuple_SET_ITEM(res,i,PyUnicode_FromString(s->status.onekeyUpgradeVersion[i]));
    // }
    return res;
}

static PyObject* Stat_tool_offset(PyStatChannel* s) { return pose(s->status.task.robotToolOffset); }

static PyObject* Stat_tool_offsets(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(MAX_TOOL_CNT);

    for (int i = 0; i < MAX_TOOL_CNT; ++i) { PyTuple_SET_ITEM(res, i, pose(s->status.toolOffset[i])); }

    return res;
}

static PyObject* Stat_user_offsets(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(MAX_FRAME_CNT);

    for (int i = 0; i < MAX_FRAME_CNT; ++i) { PyTuple_SET_ITEM(res, i, pose(s->status.userOffset[i])); }

    return res;
}

static PyObject* IO_TYPE_INDEX(IOTypeIndex& io)
{
    PyObject* res = PyTuple_New(2);
    PyTuple_SET_ITEM(res, 0, PyLong_FromLong(io.type));
    PyTuple_SET_ITEM(res, 1, PyLong_FromLong(io.index));
    return res;
}

static PyObject* Stat_is_robot_in_limited_status(PyStatChannel* s)
{
    PyObject* limited_status = PyTuple_New(9);
    PyTuple_SetItem(limited_status, 0, PyLong_FromLong(s->status.motion.percentage_mode_level == 1));
    PyTuple_SetItem(limited_status, 1, PyLong_FromLong(s->status.motion.percentage_mode_level == 2));
    PyTuple_SetItem(limited_status, 2, PyLong_FromLong(s->status.motion.percentage_mode_level == 3));
    PyTuple_SetItem(limited_status, 3, PyLong_FromLong(s->status.motion.is_momentumLimited));

    PyTuple_SetItem(limited_status, 4, PyLong_FromLong(s->status.motion.is_tcpvel_limited));
    PyTuple_SetItem(limited_status, 5, PyLong_FromLong(s->status.motion.is_robot_power_limited));
    PyTuple_SetItem(limited_status, 6, PyLong_FromLong(s->status.motion.is_safezone_limited));
    PyTuple_SetItem(limited_status, 7, PyLong_FromLong(s->status.motion.is_reduce_mode));
    PyTuple_SetItem(limited_status, 8, PyLong_FromLong(s->status.motion.three_position_enable_limit));
    return limited_status;
}

static PyObject* Stat_is_joint_pos_limited(PyStatChannel* s)
{
    PyObject* limited_status = PyTuple_New(s->status.motion.robot_joint_num);
    for (int i = 0; i < s->status.motion.robot_joint_num; i++)
    {
        double negative_limit = -360;  //s->status.motion.min_pos_limit[i];
        double positive_limit = 360;   //s->status.motion.max_pos_limit[i];
        double joint_pos = s->status.motion.joint[i].output;
        bool ret = (negative_limit < joint_pos) && (joint_pos < positive_limit);
        PyTuple_SetItem(limited_status, i, PyLong_FromLong(!ret));
    }

    return limited_status;
}

static PyObject* Stat_is_joint_vel_limited(PyStatChannel* s)
{
    PyObject* limited_status = PyTuple_New(s->status.motion.robot_joint_num);
    for (int i = 0; i < s->status.motion.robot_joint_num; i++) { PyTuple_SetItem(limited_status, i, PyLong_FromLong(s->status.motion.is_jointvel_limited[i])); }

    return limited_status;
}

static PyObject* Stat_funcdi(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(15);
    PyTuple_SetItem(res, 0, IO_TYPE_INDEX(s->status.io.funcIOMap.task_run_di));
    PyTuple_SetItem(res, 1, IO_TYPE_INDEX(s->status.io.funcIOMap.task_pause_di));
    PyTuple_SetItem(res, 2, IO_TYPE_INDEX(s->status.io.funcIOMap.task_resume_di));
    PyTuple_SetItem(res, 3, IO_TYPE_INDEX(s->status.io.funcIOMap.task_stop_di));
    PyTuple_SetItem(res, 4, IO_TYPE_INDEX(s->status.io.funcIOMap.power_on_di));
    PyTuple_SetItem(res, 5, IO_TYPE_INDEX(s->status.io.funcIOMap.power_off_di));
    PyTuple_SetItem(res, 6, IO_TYPE_INDEX(s->status.io.funcIOMap.servo_enable_di));
    PyTuple_SetItem(res, 7, IO_TYPE_INDEX(s->status.io.funcIOMap.servo_disable_di));
    PyTuple_SetItem(res, 8, IO_TYPE_INDEX(s->status.io.funcIOMap.percentage_mode_level1_di));
    PyTuple_SetItem(res, 9, IO_TYPE_INDEX(s->status.io.funcIOMap.stop_mode_di));
    PyTuple_SetItem(res, 10, IO_TYPE_INDEX(s->status.io.funcIOMap.back_to_inipos_di));
    PyTuple_SetItem(res, 11, IO_TYPE_INDEX(s->status.io.funcIOMap.percentage_mode_level2_di));
    PyTuple_SetItem(res, 12, IO_TYPE_INDEX(s->status.io.funcIOMap.clear_error_di));
    PyTuple_SetItem(res, 13, IO_TYPE_INDEX(s->status.io.funcIOMap.drag_mode_di));
    PyTuple_SetItem(res, 14, IO_TYPE_INDEX(s->status.io.funcIOMap.drag_mode_disable_di));
    return res;
}

static PyObject* Stat_funcdo(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(18);

    PyObject* idle_do = PyTuple_New(4);
    for (int i = 0; i < 4; i++) { PyTuple_SetItem(idle_do, i, IO_TYPE_INDEX(s->status.io.funcIOMap.task_idle_do[i])); }
    PyObject* paused_do = PyTuple_New(4);
    for (int i = 0; i < 4; i++) { PyTuple_SetItem(paused_do, i, IO_TYPE_INDEX(s->status.io.funcIOMap.task_paused_do[i])); }
    PyObject* running_do = PyTuple_New(4);
    for (int i = 0; i < 4; i++) { PyTuple_SetItem(running_do, i, IO_TYPE_INDEX(s->status.io.funcIOMap.task_running_do[i])); }
    PyObject* fault_do = PyTuple_New(4);
    for (int i = 0; i < 4; i++) { PyTuple_SetItem(fault_do, i, IO_TYPE_INDEX(s->status.io.funcIOMap.stat_fault_do[i])); }
    PyObject* poweron_do = PyTuple_New(4);
    for (int i = 0; i < 4; i++) { PyTuple_SetItem(poweron_do, i, IO_TYPE_INDEX(s->status.io.funcIOMap.stat_poweron_do[i])); }
    PyObject* enabled_do = PyTuple_New(4);
    for (int i = 0; i < 4; i++) { PyTuple_SetItem(enabled_do, i, IO_TYPE_INDEX(s->status.io.funcIOMap.stat_enabled_do[i])); }
    PyObject* motion_do = PyTuple_New(4);
    for (int i = 0; i < 4; i++) { PyTuple_SetItem(motion_do, i, IO_TYPE_INDEX(s->status.io.funcIOMap.stat_motion_do[i])); }
    PyObject* static_do = PyTuple_New(4);
    for (int i = 0; i < 4; i++) { PyTuple_SetItem(static_do, i, IO_TYPE_INDEX(s->status.io.funcIOMap.stat_static_do[i])); }
    PyObject* boot_do = PyTuple_New(4);
    for (int i = 0; i < 4; i++) { PyTuple_SetItem(boot_do, i, IO_TYPE_INDEX(s->status.io.funcIOMap.stat_boot_do[i])); }
    PyObject* emergency_stop_do = PyTuple_New(4);
    for (int i = 0; i < 4; i++) { PyTuple_SetItem(emergency_stop_do, i, IO_TYPE_INDEX(s->status.io.funcIOMap.stat_emergency_stop_do[i])); }
    PyObject* percentage_mode_level2_do = PyTuple_New(4);
    for (int i = 0; i < 4; i++) { PyTuple_SetItem(percentage_mode_level2_do, i, IO_TYPE_INDEX(s->status.io.funcIOMap.stat_percentage_mode_level2_do[i])); }
    PyObject* sys_protective_stop_do = PyTuple_New(4);
    for (int i = 0; i < 4; i++) { PyTuple_SetItem(sys_protective_stop_do, i, IO_TYPE_INDEX(s->status.io.funcIOMap.stat_sys_protective_stop_do[i])); }
    PyObject* initial_pose_do = PyTuple_New(4);
    for (int i = 0; i < 4; i++) { PyTuple_SetItem(initial_pose_do, i, IO_TYPE_INDEX(s->status.io.funcIOMap.stat_initial_pose_do[i])); }
    PyObject* percentage_mode_level1_do = PyTuple_New(4);
    for (int i = 0; i < 4; i++) { PyTuple_SetItem(percentage_mode_level1_do, i, IO_TYPE_INDEX(s->status.io.funcIOMap.stat_percentage_mode_level1_do[i])); }
    PyObject* drag_mode_do = PyTuple_New(4);
    for (int i = 0; i < 4; i++) { PyTuple_SetItem(drag_mode_do, i, IO_TYPE_INDEX(s->status.io.funcIOMap.stat_drag_mode_do[i])); }
    PyObject* collision_mode_do = PyTuple_New(4);
    for (int i = 0; i < 4; i++) { PyTuple_SetItem(collision_mode_do, i, IO_TYPE_INDEX(s->status.io.funcIOMap.stat_collision_mode_do[i])); }
    PyObject* manual_mode_do = PyTuple_New(4);
    for (int i = 0; i < 4; i++) { PyTuple_SetItem(manual_mode_do, i, IO_TYPE_INDEX(s->status.io.funcIOMap.stat_manual_mode_do[i])); }
    PyObject* auto_mode_do = PyTuple_New(4);
    for (int i = 0; i < 4; i++) { PyTuple_SetItem(auto_mode_do, i, IO_TYPE_INDEX(s->status.io.funcIOMap.stat_auto_mode_do[i])); }

    PyTuple_SetItem(res, 0, idle_do);
    PyTuple_SetItem(res, 1, paused_do);
    PyTuple_SetItem(res, 2, running_do);
    PyTuple_SetItem(res, 3, fault_do);
    PyTuple_SetItem(res, 4, poweron_do);
    PyTuple_SetItem(res, 5, enabled_do);
    PyTuple_SetItem(res, 6, motion_do);
    PyTuple_SetItem(res, 7, static_do);
    PyTuple_SetItem(res, 8, boot_do);
    PyTuple_SetItem(res, 9, emergency_stop_do);
    PyTuple_SetItem(res, 10, percentage_mode_level2_do);
    PyTuple_SetItem(res, 11, sys_protective_stop_do);
    PyTuple_SetItem(res, 12, initial_pose_do);
    PyTuple_SetItem(res, 13, drag_mode_do);
    PyTuple_SetItem(res, 14, collision_mode_do);
    PyTuple_SetItem(res, 15, percentage_mode_level1_do);
    PyTuple_SetItem(res, 16, manual_mode_do);
    PyTuple_SetItem(res, 17, auto_mode_do);
    return res;
}

static PyObject* Stat_safety_funcdi(PyStatChannel* s)
{
    if (s->status.cab_type == 2)
    {
        PyObject* res = short_array(s->status.safe.sFuncDISettings.diChnFunc, 8);
        return res;
    }
    return Py_None;
}

static PyObject* Stat_safety_funcdo(PyStatChannel* s)
{
    if (s->status.cab_type == 2)
    {
        PyObject* res = short_array(s->status.safe.sFuncDOSettings.doChnFunc, 8);
        return res;
    }
    return Py_None;
}

static PyObject* Stat_payload(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(2);
    PyTuple_SetItem(res, 0, PyFloat_FromDouble(s->status.motion.payload[0]));  // 默认给一号机器人的负载参数

    PyObject* com = PyTuple_New(3);
    for (int i = 0; i < 3; i++) { PyTuple_SetItem(com, i, PyFloat_FromDouble(s->status.motion.payload[1 + i])); }

    PyTuple_SetItem(res, 1, com);

    return res;
}

static PyObject* Stat_drag_near_limit(PyStatChannel* s) { return int_array(s->status.motion.dragNearLimit, s->status.motion.robot_joint_num); }

static PyObject* Stat_extio_num(PyStatChannel* s)
{
    PyObject* res;
    res = PyLong_FromLong(s->status.io.extio.extIOModCnt);
    return res;
}

static PyObject* Stat_extio_setup(PyStatChannel* s)
{
    // setup [[type, name, (comm), (di_startRegAddr, di_pinNum), (do_startRegAddr, do_pinNum), (ai_startRegAddr, ai_pinNum), (ao_startRegAddr, ao_pinNum)], ...]
    PyObject* res = PyList_New(s->status.io.extio.extIOModCnt);
    for (int i = 0; i < s->status.io.extio.extIOModCnt; ++i)
    {
        ExtIOSetup currModSetup = s->status.io.extio.extIOConfig[i].extIOSetup;

        PyObject* pyExtIOSetup = PyTuple_New(5);
        /*module extending type*/
        PyTuple_SetItem(pyExtIOSetup, 0, PyLong_FromLong(currModSetup.extType));
        /*module name*/
        PyTuple_SetItem(pyExtIOSetup, 1, PyUnicode_FromString(currModSetup.modName));
        /*comm config for ext io module*/
        if (currModSetup.extType == 0)
        {  // MOD_RTU
            PyObject* pyExtIOModComm = PyTuple_New(5);
            PyTuple_SetItem(pyExtIOModComm, 0, PyLong_FromLong(currModSetup.commInfo.rtuComm.baudrate));
            PyTuple_SetItem(pyExtIOModComm, 1, PyLong_FromLong(currModSetup.commInfo.rtuComm.databits));
            PyTuple_SetItem(pyExtIOModComm, 2, PyLong_FromLong(currModSetup.commInfo.rtuComm.slaveId));
            PyTuple_SetItem(pyExtIOModComm, 3, PyLong_FromLong(currModSetup.commInfo.rtuComm.parity));
            PyTuple_SetItem(pyExtIOModComm, 4, PyLong_FromLong(currModSetup.commInfo.rtuComm.stopbits));
            PyTuple_SetItem(pyExtIOSetup, 2, pyExtIOModComm);
        }
        else
        {
            PyObject* pyExtIOModComm = PyTuple_New(3);
            PyTuple_SetItem(pyExtIOModComm, 0, PyUnicode_FromString(currModSetup.commInfo.tcpComm.ipaddr));
            PyTuple_SetItem(pyExtIOModComm, 1, PyLong_FromLong(currModSetup.commInfo.tcpComm.port));
            PyTuple_SetItem(pyExtIOModComm, 2, PyLong_FromLong(currModSetup.commInfo.tcpComm.slaveId));
            PyTuple_SetItem(pyExtIOSetup, 2, pyExtIOModComm);
        }

        PyObject* pyPinSetup = PyList_New(4);

        PyObject* pyDIPinSetup = PyTuple_New(2);
        PyTuple_SetItem(pyDIPinSetup, 0, PyLong_FromLong(currModSetup.diSetup.startRegAddr));
        PyTuple_SetItem(pyDIPinSetup, 1, PyLong_FromLong(currModSetup.diSetup.pinNum));
        PyList_SetItem(pyPinSetup, 0, pyDIPinSetup);

        PyObject* pyDOPinSetup = PyTuple_New(2);
        PyTuple_SetItem(pyDOPinSetup, 0, PyLong_FromLong(currModSetup.doSetup.startRegAddr));
        PyTuple_SetItem(pyDOPinSetup, 1, PyLong_FromLong(currModSetup.doSetup.pinNum));
        PyList_SetItem(pyPinSetup, 1, pyDOPinSetup);

        PyObject* pyAIPinSetup = PyTuple_New(2);
        PyTuple_SetItem(pyAIPinSetup, 0, PyLong_FromLong(currModSetup.aiSetup.startRegAddr));
        PyTuple_SetItem(pyAIPinSetup, 1, PyLong_FromLong(currModSetup.aiSetup.pinNum));
        PyList_SetItem(pyPinSetup, 2, pyAIPinSetup);

        PyObject* pyAOPinSetup = PyTuple_New(2);
        PyTuple_SetItem(pyAOPinSetup, 0, PyLong_FromLong(currModSetup.aoSetup.startRegAddr));
        PyTuple_SetItem(pyAOPinSetup, 1, PyLong_FromLong(currModSetup.aoSetup.pinNum));
        PyList_SetItem(pyPinSetup, 3, pyAOPinSetup);
        /*pin setup for IO*/
        PyTuple_SetItem(pyExtIOSetup, 3, pyPinSetup);
        PyTuple_SetItem(pyExtIOSetup, 4, PyUnicode_FromString(currModSetup.ExtIOModInfo));
        PyList_SetItem(res, i, pyExtIOSetup);
    }

    return res;
}

static PyObject* Stat_extio_pinmap(PyStatChannel* s)
{
    // pinmap,with format: [[0,0,0,0], ...]
    PyObject* res = PyList_New(s->status.io.extio.extIOModCnt);
    for (int i = 0; i < s->status.io.extio.extIOModCnt; ++i)
    {
        PyObject* pyExtIOMap = PyTuple_New(4);
        ExtIOMap currModMap = s->status.io.extio.extIOConfig[i].extIOMap;
        PyTuple_SetItem(pyExtIOMap, 0, PyLong_FromLong(currModMap.diStartIdx));
        PyTuple_SetItem(pyExtIOMap, 1, PyLong_FromLong(currModMap.doStartIdx));
        PyTuple_SetItem(pyExtIOMap, 2, PyLong_FromLong(currModMap.aiStartIdx));
        PyTuple_SetItem(pyExtIOMap, 3, PyLong_FromLong(currModMap.aoStartIdx));

        PyList_SetItem(res, i, pyExtIOMap);
    }
    return res;
}

static PyObject* Stat_extio_mode(PyStatChannel* s)
{
    // extio_mode 0/1
    PyObject* res = PyLong_FromLong(s->status.io.extio.extIOStat.status);
    return res;
}

static PyObject* Stat_extio_stat(PyStatChannel* s)
{
    // extio_stat [[di], [do], [ai], [ao]]
    int totalDINum = 0;
    int totalDONum = 0;
    int totalAINum = 0;
    int totalAONum = 0;
    for (int i = 0; i < s->status.io.extio.extIOModCnt; ++i)
    {
        ExtIOSetup currModSetup = s->status.io.extio.extIOConfig[i].extIOSetup;
        totalDINum += currModSetup.diSetup.pinNum;
        totalDONum += currModSetup.doSetup.pinNum;
        totalAINum += currModSetup.aiSetup.pinNum;
        totalAONum += currModSetup.aoSetup.pinNum;
    }

    PyObject* pyExtIOStat = PyList_New(4);
    PyList_SetItem(pyExtIOStat, 0, int_array(s->status.io.extio.extIOStat.extDI, totalDINum));
    PyList_SetItem(pyExtIOStat, 1, int_array(s->status.io.extio.extIOStat.extDO, totalDONum));
    PyList_SetItem(pyExtIOStat, 2, double_array(s->status.io.extio.extIOStat.extAI, totalAINum));
    PyList_SetItem(pyExtIOStat, 3, double_array(s->status.io.extio.extIOStat.extAO, totalAONum));
    return pyExtIOStat;
}

static PyObject* Stat_auto_work(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(2);
    PyTuple_SetItem(res, 0, PyLong_FromLong(s->status.task.autoWork.enable));
    PyTuple_SetItem(res, 1, PyUnicode_FromString(s->status.task.autoWork.filename));
    return res;
}

static PyObject* Stat_backup_setting(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(2);
    PyTuple_SetItem(res, 0, PyLong_FromLong(s->status.task.backupSetting.enable));
    PyTuple_SetItem(res, 1, PyFloat_FromDouble(s->status.task.backupSetting.interval));
    return res;
}

static PyObject* Stat_slave_config(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(2);
    PyTuple_SetItem(res, 0, PyLong_FromLong(s->status.mbSlaveCommType));

    if (s->status.mbSlaveCommType == 0)
    {  // modbus rtu
        PyObject* mbComm = PyDict_New();
        PyDict_SetItemString(mbComm, "slaveId", PyLong_FromLong(s->status.mbSlaveCommInfo.rtuComm.slaveId));
        PyDict_SetItemString(mbComm, "baudrate", PyLong_FromLong(s->status.mbSlaveCommInfo.rtuComm.baudrate));
        PyDict_SetItemString(mbComm, "databit", PyLong_FromLong(s->status.mbSlaveCommInfo.rtuComm.databits));
        PyDict_SetItemString(mbComm, "stopbit", PyLong_FromLong(s->status.mbSlaveCommInfo.rtuComm.stopbits));
        PyDict_SetItemString(mbComm, "parity", PyLong_FromLong(s->status.mbSlaveCommInfo.rtuComm.parity));
        PyTuple_SetItem(res, 1, mbComm);
    }
    else if (s->status.mbSlaveCommType == 1)
    {
        PyObject* mbComm = PyDict_New();
        PyDict_SetItemString(mbComm, "ipaddr", PyUnicode_FromString(s->status.mbSlaveCommInfo.tcpComm.ipaddr));
        PyDict_SetItemString(mbComm, "port", PyLong_FromLong(s->status.mbSlaveCommInfo.tcpComm.port));
        PyTuple_SetItem(res, 1, mbComm);
    }

    return res;
}

static PyObject* Stat_position(PyStatChannel* s) { return pose(s->status.motion.traj.position); }

static PyObject* Stat_dtg(PyStatChannel* s) { return pose(s->status.motion.traj.dtg); }

static PyObject* Stat_actual_position(PyStatChannel* s) { return pose(s->status.motion.traj.actualPosition); }

static PyObject* Stat_position_desired(PyStatChannel* s) { return pose(s->status.motion.traj.position_desired); }

static PyObject* Stat_position_seg_target(PyStatChannel* s) { return pose(s->status.motion.traj.curSegTargetPose); }

static PyObject* Stat_installation_angle(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(2);
    PyObject* quat = PyTuple_New(4);
    PyTuple_SetItem(quat, 0, PyFloat_FromDouble(0));
    PyTuple_SetItem(quat, 1, PyFloat_FromDouble(0));
    PyTuple_SetItem(quat, 2, PyFloat_FromDouble(0));
    PyTuple_SetItem(quat, 3, PyFloat_FromDouble(0));
    PyTuple_SetItem(res, 0, quat);

    PyObject* appang = PyTuple_New(3);
    PyTuple_SetItem(appang, 0, PyFloat_FromDouble(s->status.userOffset[s->status.motion.base_frame_id].a));  //s->status.motion.baseOffset.appang[0]));
    PyTuple_SetItem(appang, 1, PyFloat_FromDouble(s->status.userOffset[s->status.motion.base_frame_id].b));  //s->status.motion.baseOffset.appang[1]));
    PyTuple_SetItem(appang, 2, PyFloat_FromDouble(s->status.userOffset[s->status.motion.base_frame_id].c));  //s->status.motion.baseOffset.appang[2]));
    PyTuple_SetItem(res, 1, appang);

    return res;
}

static PyObject* Stat_current_tool_id(PyStatChannel* s)
{
    PyObject* res;
    res = PyLong_FromLong(s->status.motion.currentToolId);
    return res;
}

static PyObject* Stat_current_user_id(PyStatChannel* s)
{
    PyObject* res;
    res = PyLong_FromLong(s->status.motion.currentUserId);
    return res;
}

static PyObject* Stat_servo_upGrade_percentage(PyStatChannel* s)
{
    PyObject* res;
    res = PyLong_FromLong(s->status.servo_upGrade_percentage_total);
    return res;
}

static PyObject* Stat_robot_model_data(PyStatChannel* s)
{
    PyObject* res = PyDict_New();
    PyDict_SetItemString(res, "model", PyLong_FromLong(s->status.motion.robot_model_data.model));
    PyDict_SetItemString(res, "payload", PyFloat_FromDouble(s->status.motion.robot_model_data.payload));
    PyDict_SetItemString(res, "maxTrajVel", PyFloat_FromDouble(s->status.motion.robot_model_data.maxTrajVel));
    PyDict_SetItemString(res, "maxTrajAcc", PyFloat_FromDouble(s->status.motion.robot_model_data.maxTrajAcc));
    PyDict_SetItemString(res, "maxTrajVel_ori", PyFloat_FromDouble(s->status.motion.robot_model_data.maxTrajVel_ori));
    PyDict_SetItemString(res, "maxTrajAcc_ori", PyFloat_FromDouble(s->status.motion.robot_model_data.maxTrajAcc_ori));

    PyDict_SetItemString(res, "minMomentum", PyFloat_FromDouble(s->status.motion.robot_model_data.minMomentum));
    PyDict_SetItemString(res, "maxMomentum", PyFloat_FromDouble(s->status.motion.robot_model_data.maxMomentum));
    PyDict_SetItemString(res, "minRobotPower", PyFloat_FromDouble(s->status.motion.robot_model_data.minRobotPower));
    PyDict_SetItemString(res, "maxRobotPower", PyFloat_FromDouble(s->status.motion.robot_model_data.maxRobotPower));
    PyDict_SetItemString(res, "minReduceMomentum", PyFloat_FromDouble(s->status.motion.robot_model_data.minReduceMomentum));
    PyDict_SetItemString(res, "maxReduceMomentum", PyFloat_FromDouble(s->status.motion.robot_model_data.maxReduceMomentum));
    PyDict_SetItemString(res, "minReduceRobotPower", PyFloat_FromDouble(s->status.motion.robot_model_data.minReduceRobotPower));
    PyDict_SetItemString(res, "maxReduceRobotPower", PyFloat_FromDouble(s->status.motion.robot_model_data.maxReduceRobotPower));

    PyObject* minJointPosLimits = PyTuple_New(s->status.motion.robot_joint_num);
    for (int i = 0; i < s->status.motion.robot_joint_num; i++)
    {
        PyTuple_SetItem(minJointPosLimits, i, PyFloat_FromDouble(s->status.motion.robot_model_data.minJointPosLimit[i]));
    }
    PyDict_SetItemString(res, "minJointPosLimits", minJointPosLimits);

    PyObject* maxJointPosLimits = PyTuple_New(s->status.motion.robot_joint_num);
    for (int i = 0; i < s->status.motion.robot_joint_num; i++)
    {
        PyTuple_SetItem(maxJointPosLimits, i, PyFloat_FromDouble(s->status.motion.robot_model_data.maxJointPosLimit[i]));
    }
    PyDict_SetItemString(res, "maxJointPosLimits", maxJointPosLimits);

    PyObject* maxJointVels = PyTuple_New(s->status.motion.robot_joint_num);
    for (int i = 0; i < s->status.motion.robot_joint_num; i++)
    {
        PyTuple_SetItem(maxJointVels, i, PyFloat_FromDouble(s->status.motion.robot_model_data.maxJointVel[i]));
    }
    PyDict_SetItemString(res, "maxJointVels", maxJointVels);

    PyObject* maxJointAccs = PyTuple_New(s->status.motion.robot_joint_num);
    for (int i = 0; i < s->status.motion.robot_joint_num; i++)
    {
        PyTuple_SetItem(maxJointAccs, i, PyFloat_FromDouble(s->status.motion.robot_model_data.maxJointAcc[i]));
    }
    PyDict_SetItemString(res, "maxJointAccs", maxJointAccs);

    PyObject* maxGearboxTorq = PyTuple_New(s->status.motion.robot_joint_num);
    for (int i = 0; i < s->status.motion.robot_joint_num; i++)
    {
        PyTuple_SetItem(maxGearboxTorq, i, PyFloat_FromDouble(s->status.motion.robot_model_data.gearboxMaxTorque[i]));
    }
    PyDict_SetItemString(res, "maxGearboxTorq", maxGearboxTorq);

    PyObject* motorSupplierId = PyTuple_New(s->status.motion.robot_joint_num);
    for (int i = 0; i < s->status.motion.robot_joint_num; i++)
    {
        PyTuple_SetItem(motorSupplierId, i, PyLong_FromLong(s->status.motion.robot_model_data.motorSupplierId[i]));
    }
    PyDict_SetItemString(res, "motorSupplierId", motorSupplierId);

    PyObject* tioInfo = PyTuple_New(4);
    PyTuple_SetItem(tioInfo, 0, PyLong_FromLong(s->status.motion.robot_model_data.tioInfo.diNum));
    PyTuple_SetItem(tioInfo, 1, PyLong_FromLong(s->status.motion.robot_model_data.tioInfo.doNum));
    PyTuple_SetItem(tioInfo, 2, PyLong_FromLong(s->status.motion.robot_model_data.tioInfo.aiNum));
    PyTuple_SetItem(tioInfo, 3, PyLong_FromLong(s->status.motion.robot_model_data.tioInfo.aoNum));
    PyDict_SetItemString(res, "tioInfo", tioInfo);

    return res;
}

static PyObject* Stat_torqsensor(PyStatChannel* s)
{
    PyObject* res = PyList_New(2);

    /*set config data*/
    PyObject* config = PyTuple_New(3);
    SensorConfig sensorCfg = s->status.motion.sensor.sensorConfig;
    PyTuple_SetItem(config, 0, PyLong_FromLong(sensorCfg.commType));
    if (sensorCfg.commType == 1)
    {
        PyObject* pySensorComm = PyTuple_New(4);
        // PyTuple_SetItem(pySensorComm, 0, PyLong_FromLong(sensorCfg.commCfg.rtuComm.baudrate));
        // PyTuple_SetItem(pySensorComm, 1, PyLong_FromLong(sensorCfg.commCfg.rtuComm.databits));
        // PyTuple_SetItem(pySensorComm, 2, PyLong_FromLong(sensorCfg.commCfg.rtuComm.stopbits));
        // PyTuple_SetItem(pySensorComm, 3, PyLong_FromLong(sensorCfg.commCfg.rtuComm.parity));
        PyTuple_SetItem(config, 1, pySensorComm);
    }
    else
    {
        PyObject* pySensorComm = PyTuple_New(2);
        // PyTuple_SetItem(pySensorComm, 0, PyUnicode_FromString(sensorCfg.commCfg.tcpComm.ipaddr));
        // PyTuple_SetItem(pySensorComm, 1, PyLong_FromLong(sensorCfg.commCfg.tcpComm.port));
        PyTuple_SetItem(config, 1, pySensorComm);
    }
    PyObject* pySensorPayload = PyTuple_New(2);
    // PyTuple_SetItem(pySensorPayload, 0, PyFloat_FromDouble(sensorCfg.payload.m));
    // PyTuple_SetItem(pySensorPayload, 1, double_array(sensorCfg.payload.p, 3));
    PyTuple_SetItem(config, 2, pySensorPayload);
    PyList_SetItem(res, 0, config);

    /*set status data*/
    PyObject* status = PyTuple_New(5);
    PyTuple_SetItem(status, 0, PyLong_FromLong(s->status.motion.sensor.sensorStatus.status));
    PyTuple_SetItem(status, 1, PyLong_FromLong(s->status.motion.sensor.sensorStatus.errCode));
    PyTuple_SetItem(status, 2, double_array(s->status.motion.sensor.sensorStatus.actTorque, CART_DIM));
    PyTuple_SetItem(status, 3, double_array(s->status.motion.sensor.sensorStatus.torque, CART_DIM));
    PyTuple_SetItem(status, 4, double_array(s->status.motion.sensor.sensorStatus.realTorque, CART_DIM));
    PyList_SetItem(res, 1, status);
    return res;
}

static PyObject* Stat_tool_payload(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(2);
    PyTuple_SetItem(res, 0, PyFloat_FromDouble(s->status.payload[0].m));
    PyTuple_SetItem(res, 1, double_array(s->status.payload[0].p, 3));
    return res;
}

static PyObject* Stat_torque_sensor_soft_limit(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(CART_DIM);
    for (int i = 0; i < CART_DIM; i++) { PyTuple_SetItem(res, i, PyFloat_FromDouble(s->status.motion.torqueSensorSoftLimit[i])); }
    return res;
}

static PyObject* Stat_admittance_ctrl_frame(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(1);
    PyTuple_SetItem(res, 0, PyLong_FromLong(s->status.motion.ftFrame));
    return res;
}

static PyObject* Stat_torque_sensor_filter(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(1);
    PyTuple_SetItem(res, 0, PyFloat_FromDouble(s->status.motion.torqueSensorFilter));
    return res;
}

static PyObject* Stat_torque_sensor_brand(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(1);
    PyTuple_SetItem(res, 0, PyFloat_FromDouble(s->status.motion.sensor.sensorConfig.torqsensorBrand));
    return res;
}

static PyObject* Stat_vel_compliant_ctrl(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(5);
    for (int i = 0; i < 5; i++) { PyTuple_SetItem(res, i, PyFloat_FromDouble(s->status.motion.velCompliantCtrl[i])); }
    return res;
}

static PyObject* Stat_compliant_condition(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(CART_DIM);
    for (int i = 0; i < CART_DIM; i++) { PyTuple_SetItem(res, i, PyFloat_FromDouble(s->status.motion.compliantCondition[i])); }
    return res;
}

static PyObject* Stat_admit_ctrl_config(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(CART_DIM);
    for (int i = 0; i < CART_DIM; i++)
    {
        PyObject* axisFtCfgObj = PyTuple_New(5);
        PyTuple_SetItem(axisFtCfgObj, 0, PyLong_FromLong(s->status.motion.admitFtConfig[i].enableFt));
        PyTuple_SetItem(axisFtCfgObj, 1, PyFloat_FromDouble(s->status.motion.admitFtConfig[i].ftUser));
        PyTuple_SetItem(axisFtCfgObj, 2, PyFloat_FromDouble(s->status.motion.admitFtConfig[i].ftReboundFK));
        PyTuple_SetItem(axisFtCfgObj, 3, PyFloat_FromDouble(s->status.motion.admitFtConfig[i].ftConstant));
        PyTuple_SetItem(axisFtCfgObj, 4, PyLong_FromLong(s->status.motion.admitFtConfig[i].enableNTrack));
        PyTuple_SetItem(res, i, axisFtCfgObj);
    }
    return res;
}

static PyObject* Stat_compliant_type_enable(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(2);
    PyTuple_SetItem(res, 0, PyLong_FromLong(s->status.motion.compliantType));
    PyTuple_SetItem(res, 1, PyLong_FromLong(s->status.motion.compliantEnable));
    return res;
}

static PyObject* Stat_admit_axis_opt(PyStatChannel* s) { return int_array(s->status.motion.admit_axis_opt, CART_DIM); }

static PyObject* Stat_admittance_enabled(PyStatChannel* s)
{
    int enabled = 0;
    if (s->status.motion.traj.mode == ZUC_TRAJ_MODE_ADMITTANCE)
        enabled = 1;

    return PyLong_FromLong(enabled);
}

static PyObject* Stat_scb_stick_locked(PyStatChannel* s)
{
    if (s->status.cab_type >= 2)
    {
        int scb_stick_locked = 0;
        if (s->status.scb_stick_locked == 1)
        {
            scb_stick_locked = 1;
        }
        return PyLong_FromLong(scb_stick_locked);
    }

    return Py_None;
}

static PyObject* Stat_shrunken_pose(PyStatChannel* s) { return double_array(s->status.motion.shrunkenPose, ZUCMOT_ROBOT_MAX_JOINTS); }

static PyObject* Stat_stretched_pose(PyStatChannel* s) { return double_array(s->status.motion.stretchedPose, ZUCMOT_ROBOT_MAX_JOINTS); }

static PyObject* Stat_initial_pose(PyStatChannel* s) { return double_array(s->status.motion.initialPose, ZUCMOT_ROBOT_MAX_JOINTS); }

static PyObject* Stat_init_pose_tol(PyStatChannel* s) { return Py_BuildValue("d", s->status.motion.initPoseTol); }

static PyObject* Stat_robot_safety(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(7);

    for (int i = 0; i < 6; ++i)
    {
        PyObject* rotsft = PyDict_New();
        PyDict_SetItemString(rotsft, "custome", PyLong_FromLong(s->status.robotSafe[i].custome));
        PyDict_SetItemString(rotsft, "lastCustome", PyLong_FromLong(s->status.robotSafe[i].lastCustome));
        PyDict_SetItemString(rotsft, "momentumLimit", PyFloat_FromDouble(s->status.robotSafe[i].momentumLimit));
        PyDict_SetItemString(rotsft, "tcpVelLimit", PyFloat_FromDouble(s->status.robotSafe[i].tcpVelLimit));
        PyDict_SetItemString(rotsft, "robotPowerLimit", PyFloat_FromDouble(s->status.robotSafe[i].robotPowerLimit));
        PyDict_SetItemString(rotsft, "stoppingDistance", PyFloat_FromDouble(s->status.robotSafe[i].stoppingDistance));
        PyDict_SetItemString(rotsft, "stoppingTime", PyFloat_FromDouble(s->status.robotSafe[i].stoppingTime));
        PyTuple_SetItem(res, i, rotsft);
    }

    return res;
}

static PyObject* Stat_reduce_safety(PyStatChannel* s)
{
    PyObject* res = PyDict_New();
    PyDict_SetItemString(res, "tcp_speed", PyFloat_FromDouble(s->status.reduceSafe.tcp_speed));
    PyDict_SetItemString(res, "elbow_speed", PyFloat_FromDouble(s->status.reduceSafe.elbow_speed));
    PyDict_SetItemString(res, "momentum_limit", PyFloat_FromDouble(s->status.reduceSafe.momentum_limit));
    PyDict_SetItemString(res, "power_limit", PyFloat_FromDouble(s->status.reduceSafe.power_limit));
    PyDict_SetItemString(res, "stopping_time", PyFloat_FromDouble(s->status.reduceSafe.stopping_time));
    PyDict_SetItemString(res, "stopping_dist", PyFloat_FromDouble(s->status.reduceSafe.stopping_dist));
    return res;
}

static PyObject* Stat_drag_speed_limit(PyStatChannel* s)
{
    PyObject* res = PyFloat_FromDouble(s->status.motion.dragTcpSpeedLimit);
    return res;
}

static PyObject* Stat_step_status(PyStatChannel* s)
{
    PyObject* res = PyList_New(3);
    PyList_SetItem(res, 0, PyLong_FromLong(s->status.stepStatus.isSteping));
    PyList_SetItem(res, 1, PyLong_FromLong(s->status.stepStatus.programRunTrigger));
    PyList_SetItem(res, 2, PyLong_FromLong(s->status.stepStatus.stepEnd));
    return res;
}

static PyObject* Stat_collision_option(PyStatChannel* s)
{
    PyObject* res = PyList_New(3);
    PyList_SetItem(res, 0, PyLong_FromLong(s->status.task.clsnDetectMethod));
    PyList_SetItem(res, 1, PyLong_FromLong(s->status.task.clsnReactTypeWhenProgRun));
    PyList_SetItem(res, 2, PyFloat_FromDouble(s->status.task.clsnReactReboundAngle));
    return res;
}

static PyObject* Stat_sub_thread_state(PyStatChannel* s)
{
    PyObject* res = PyList_New(5);
    PyList_SetItem(res, 0, PyUnicode_FromString(s->status.sub_thread_state[0]));
    PyList_SetItem(res, 1, PyUnicode_FromString(s->status.sub_thread_state[1]));
    PyList_SetItem(res, 2, PyUnicode_FromString(s->status.sub_thread_state[2]));
    PyList_SetItem(res, 3, PyUnicode_FromString(s->status.sub_thread_state[3]));
    PyList_SetItem(res, 4, PyUnicode_FromString(s->status.sub_thread_state[4]));

    return res;
}

static PyObject* Stat_joint_safety(PyStatChannel* s)
{
    int robot_joint_num = s->status.ext_motion[0].robot_joint_num;
    PyObject* res = PyTuple_New(2 * robot_joint_num);
    // 1-robot_joint_num 当前设置， robot_joint_num+1-robot_joint_num*2 机型文件设置
    auto& rb = s->status.ext_motion[0];
    // 当前设置

    // 机型默认设置
    for (int i = 0; i < robot_joint_num; ++i)
    {
        auto& model = rb.robot_model_data;
        PyObject* rotsft = PyDict_New();
        PyDict_SetItemString(rotsft, "jointNum", PyLong_FromLong(i));
        PyDict_SetItemString(rotsft, "jointVelLimit", PyFloat_FromDouble(model.maxJointVel[i]));
        PyDict_SetItemString(rotsft, "jointErrLimit", PyFloat_FromDouble(80));  //FIXME
        PyObject* jpl = PyDict_New();
        PyDict_SetItemString(jpl, "positive_limit", PyFloat_FromDouble(model.maxJointPosLimit[i]));
        PyDict_SetItemString(jpl, "negative_limit", PyFloat_FromDouble(model.minJointPosLimit[i]));
        PyDict_SetItemString(jpl, "joint_id", PyLong_FromLong(i));
        PyDict_SetItemString(rotsft, "posLimt", jpl);
        PyTuple_SetItem(res, robot_joint_num + i, rotsft);
    }

    return res;
}

static PyObject* Stat_safe_zone(PyStatChannel* s)
{
    SafeZone zone = s->status.safe.safetyZone;
    PyObject* safeZone = PyDict_New();
    PyDict_SetItemString(safeZone, "autoEnable", PyLong_FromLong(s->status.safe.safeZoneAutoEnable));
    PyDict_SetItemString(safeZone, "openEnable", PyLong_FromLong(s->status.safe.safeZoneOpenEnable));
    PyDict_SetItemString(safeZone, "safeZoneMode", PyLong_FromLong(s->status.safe.safetyZone.safeZoneMode));
    PyDict_SetItemString(safeZone, "elbowPosLimitEnable", PyLong_FromLong(s->status.safe.safetyZone.elbow_pos_limit_enable));
    PyDict_SetItemString(safeZone, "wristPosLimitEnable", PyLong_FromLong(s->status.safe.safetyZone.wrist_pos_limit_enable));
    PyObject* planes = PyTuple_New(6);
    for (int i = 0; i < 6; i++)
    {
        PyObject* plane = PyDict_New();
        PyDict_SetItemString(plane, "planeEnable", PyLong_FromLong(s->status.safe.safetyZone.zone.plane[i].enable));
        PyDict_SetItemString(plane, "planeName", Py_BuildValue("s", s->status.safe.safetyZone.zone.plane[i].name));
        PyDict_SetItemString(plane, "safeDist", PyLong_FromLong(s->status.safe.safetyZone.zone.plane[i].safeD));
        PyObject* safePoint = PyDict_New();
        PyDict_SetItemString(safePoint, "x", PyFloat_FromDouble(zone.zone.plane[i].safePoint.point.x));
        PyDict_SetItemString(safePoint, "y", PyFloat_FromDouble(zone.zone.plane[i].safePoint.point.y));
        PyDict_SetItemString(safePoint, "z", PyFloat_FromDouble(zone.zone.plane[i].safePoint.point.z));
        PyDict_SetItemString(safePoint, "a", PyFloat_FromDouble(zone.zone.plane[i].safePoint.rpy.y));
        PyDict_SetItemString(safePoint, "b", PyFloat_FromDouble(zone.zone.plane[i].safePoint.rpy.p));
        PyDict_SetItemString(safePoint, "c", PyFloat_FromDouble(zone.zone.plane[i].safePoint.rpy.r));
        PyDict_SetItemString(plane, "safePoint", safePoint);
        PyObject* planePoints = PyTuple_New(3);

        for (int j = 0; j < 3; j++)
        {
            PyObject* planePoint = PyDict_New();
            PyDict_SetItemString(planePoint, "x", PyFloat_FromDouble(zone.zone.plane[i].planePoints[j].point.x));
            PyDict_SetItemString(planePoint, "y", PyFloat_FromDouble(zone.zone.plane[i].planePoints[j].point.y));
            PyDict_SetItemString(planePoint, "z", PyFloat_FromDouble(zone.zone.plane[i].planePoints[j].point.z));
            PyDict_SetItemString(planePoint, "a", PyFloat_FromDouble(zone.zone.plane[i].planePoints[j].rpy.y));
            PyDict_SetItemString(planePoint, "b", PyFloat_FromDouble(zone.zone.plane[i].planePoints[j].rpy.p));
            PyDict_SetItemString(planePoint, "c", PyFloat_FromDouble(zone.zone.plane[i].planePoints[j].rpy.r));
            PyTuple_SetItem(planePoints, j, planePoint);
        }
        PyDict_SetItemString(plane, "planePoints", planePoints);
        PyTuple_SetItem(planes, i, plane);
    }
    PyDict_SetItemString(safeZone, "planes", planes);
    return safeZone;
}

static PyObject* Stat_kine_lib_version(PyStatChannel* s)
{
    // @shixiaoli 待库更新后恢复
    // get_kine_lib_version();
    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject* Stat_vrep_safe_simulation_information(PyStatChannel* s)
{
    PyObject* Vrep_information = PyDict_New();
    // zuc_traj_verp_simulation_safe_information verp_safe_information = s->status.motion.verp_safe_information;
    // PyDict_SetItemString(Vrep_information, "elbow_center_offset", PyFloat_FromDouble(s->status.motion.elbow_center_offset / 1000));
    // PyDict_SetItemString(Vrep_information, "elbow_sphere_radius", PyFloat_FromDouble(s->status.motion.elbow_sphere_radius / 1000));
    // PyObject* planes = PyTuple_New(6);
    // for (int i = 0; i < 6; i++)
    // {
    //     PyObject* plane = PyDict_New();
    //     PyDict_SetItemString(plane, "planeEnable", PyLong_FromLong(verp_safe_information.plane[i].enable));
    //     PyObject* safeZone = PyDict_New();
    //     PyDict_SetItemString(safeZone, "x", PyFloat_FromDouble(verp_safe_information.plane[i].planePoints.x));
    //     PyDict_SetItemString(safeZone, "y", PyFloat_FromDouble(verp_safe_information.plane[i].planePoints.y));
    //     PyDict_SetItemString(safeZone, "z", PyFloat_FromDouble(verp_safe_information.plane[i].planePoints.z));
    //     PyDict_SetItemString(safeZone, "a", PyFloat_FromDouble(verp_safe_information.plane[i].plane_Xyz.x));
    //     PyDict_SetItemString(safeZone, "b", PyFloat_FromDouble(verp_safe_information.plane[i].plane_Xyz.y));
    //     PyDict_SetItemString(safeZone, "c", PyFloat_FromDouble(verp_safe_information.plane[i].plane_Xyz.z));
    //     PyDict_SetItemString(plane, "safeZone", safeZone);
    //     PyTuple_SetItem(planes, i, plane);
    // }
    // PyDict_SetItemString(Vrep_information, "planes", planes);
    // PyObject* tool_cone_dir = PyDict_New();
    // PyDict_SetItemString(tool_cone_dir, "x_y_cone", PyFloat_FromDouble(verp_safe_information.tool_cone_dir.x_y_cone));
    // PyDict_SetItemString(tool_cone_dir, "z_cone", PyFloat_FromDouble(verp_safe_information.tool_cone_dir.z_cone));
    // PyObject* cone_xyz = PyDict_New();
    // PyDict_SetItemString(cone_xyz, "a", PyFloat_FromDouble(verp_safe_information.tool_cone_dir.cone_xyz.x));
    // PyDict_SetItemString(cone_xyz, "b", PyFloat_FromDouble(verp_safe_information.tool_cone_dir.cone_xyz.y));
    // PyDict_SetItemString(cone_xyz, "c", PyFloat_FromDouble(verp_safe_information.tool_cone_dir.cone_xyz.z));
    // PyDict_SetItemString(tool_cone_dir, "cone_xyz", cone_xyz);
    // PyObject* tool_dir_xyz = PyDict_New();
    // PyDict_SetItemString(tool_dir_xyz, "a", PyFloat_FromDouble(verp_safe_information.tool_cone_dir.tool_dir_xyz.x));
    // PyDict_SetItemString(tool_dir_xyz, "b", PyFloat_FromDouble(verp_safe_information.tool_cone_dir.tool_dir_xyz.y));
    // PyDict_SetItemString(tool_dir_xyz, "c", PyFloat_FromDouble(verp_safe_information.tool_cone_dir.tool_dir_xyz.z));
    // PyDict_SetItemString(tool_cone_dir, "tool_dir_xyz", tool_dir_xyz);
    // PyDict_SetItemString(Vrep_information, "tool_cone_dir", tool_cone_dir);

    return Vrep_information;
}

static PyObject* Stat_elbow_pos(PyStatChannel* s)
{
    PyObject* carte_elbow_pos = PyTuple_New(CART_DIM);
    ZucPose carte_elbow_pos_cmd = s->status.motion.carte_elbow_pos_cmd;
    PyTuple_SetItem(carte_elbow_pos, 0, PyFloat_FromDouble(carte_elbow_pos_cmd.tran.x));
    PyTuple_SetItem(carte_elbow_pos, 1, PyFloat_FromDouble(carte_elbow_pos_cmd.tran.y));
    PyTuple_SetItem(carte_elbow_pos, 2, PyFloat_FromDouble(carte_elbow_pos_cmd.tran.z));
    PyTuple_SetItem(carte_elbow_pos, 3, PyFloat_FromDouble(carte_elbow_pos_cmd.a));
    PyTuple_SetItem(carte_elbow_pos, 4, PyFloat_FromDouble(carte_elbow_pos_cmd.b));
    PyTuple_SetItem(carte_elbow_pos, 5, PyFloat_FromDouble(carte_elbow_pos_cmd.c));
    return carte_elbow_pos;
}

static PyObject* Stat_monitor_data(PyStatChannel* s)
{
    PyObject* res = PyList_New(11);
    PyList_SetItem(res, 0, PyLong_FromLong(s->status.monitor.scb_hw_version));
    PyList_SetItem(res, 1, PyLong_FromLong(s->status.monitor.scb_sw_version));
    PyList_SetItem(res, 2, PyFloat_FromDouble(s->status.monitor.cabTemperature));
    PyList_SetItem(res, 3, PyFloat_FromDouble(s->status.monitor.robotAveragePower));
    PyList_SetItem(res, 4, PyFloat_FromDouble(s->status.monitor.robotAverageCurrent));
    PyObject* joints = PyList_New(s->status.motion.robot_joint_num);
    for (int i = 0; i < s->status.motion.robot_joint_num; i++)
    {
        PyObject* oneJoint = PyTuple_New(11);
        PyTuple_SetItem(oneJoint, 0, PyFloat_FromDouble(s->status.monitor.jointMonitorData[i].instCurrent));
        PyTuple_SetItem(oneJoint, 1, PyFloat_FromDouble(s->status.monitor.jointMonitorData[i].instVoltage));
        PyTuple_SetItem(oneJoint, 2, PyFloat_FromDouble(s->status.monitor.jointMonitorData[i].instTemperature));
        PyTuple_SetItem(oneJoint, 3, PyFloat_FromDouble(s->status.monitor.jointMonitorData[i].insAveragePower));
        PyTuple_SetItem(oneJoint, 4, PyFloat_FromDouble(s->status.monitor.jointMonitorData[i].currentFluctuation));
        PyTuple_SetItem(oneJoint, 5, PyFloat_FromDouble(s->status.monitor.jointMonitorData[i].sumRunningCircles));
        PyTuple_SetItem(oneJoint, 6, PyFloat_FromDouble(s->status.monitor.jointMonitorData[i].sumRunningTime));
        PyTuple_SetItem(oneJoint, 7, PyFloat_FromDouble(s->status.monitor.jointMonitorData[i].curRunningCircles));
        PyTuple_SetItem(oneJoint, 8, PyFloat_FromDouble(s->status.monitor.jointMonitorData[i].curRunningTime));
        PyTuple_SetItem(oneJoint, 9, PyFloat_FromDouble(s->status.monitor.jointMonitorData[i].jointTorque));
        PyTuple_SetItem(oneJoint, 10, PyFloat_FromDouble(s->status.monitor.jointMonitorData[i].jointTorqueCmd));
        PyList_SetItem(joints, i, oneJoint);
    }
    PyList_SetItem(res, 5, joints);
    PyList_SetItem(res, 6, PyLong_FromLong(s->status.monitor.cabinetID));
    PyList_SetItem(res, 7, PyLong_FromLong(s->status.monitor.currRunTime));
    PyList_SetItem(res, 8, PyLong_FromLong(s->status.monitor.accuRunTime));
    PyList_SetItem(res, 9, PyFloat_FromDouble(s->status.monitor.robotVoltage));
    PyList_SetItem(res, 10, PyUnicode_FromString(s->status.monitor.scb_ver_str));

    return res;
}

static PyObject* Stat_servo_data(PyStatChannel* s)
{
    PyObject* joints = PyList_New(s->status.motion.robot_joint_num);
    for (int i = 0; i < s->status.motion.robot_joint_num; i++)
    {
        PyObject* oneJoint = PyTuple_New(4);
        PyTuple_SetItem(oneJoint, 0, PyFloat_FromDouble(s->status.monitor.jointMonitorData[i].positionDiff));
        PyTuple_SetItem(oneJoint, 1, PyFloat_FromDouble(s->status.monitor.jointMonitorData[i].dualEncoderDiff));
        PyTuple_SetItem(oneJoint, 2, PyFloat_FromDouble(s->status.monitor.jointMonitorData[i].jointDcVol));
        PyTuple_SetItem(oneJoint, 3, PyFloat_FromDouble(s->status.monitor.jointMonitorData[i].reserved));
        PyList_SetItem(joints, i, oneJoint);
    }

    return joints;
}

static PyObject* Stat_percentage_mode_level_val(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(2);
    PyTuple_SetItem(res, 0, PyFloat_FromDouble(s->status.motion.percentage_mode_level1_val));
    PyTuple_SetItem(res, 1, PyFloat_FromDouble(s->status.motion.percentage_mode_level2_val));
    return res;
}

static PyObject* Stat_free_button_opt(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(1);
    PyTuple_SetItem(res, 0, PyLong_FromLong(s->status.tio[0].freeButtonOpt));
    return res;
}

static PyObject* Stat_free_prog_button_opt(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(2);
    PyTuple_SetItem(res, 0, PyLong_FromLong(s->status.tio[0].secondfreeButtonOpt));
    PyTuple_SetItem(res, 1, PyLong_FromLong(s->status.tio[0].progButtonOpt));
    return res;
}

static PyObject* Stat_point_button_opt(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(1);
    PyTuple_SetItem(res, 0, PyLong_FromLong(s->status.tio[0].pointButtonOpt));
    return res;
}

static PyObject* Stat_current_robot_model(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(1);
    PyTuple_SetItem(res, 0, PyLong_FromLong(s->status.motion.robot_serial_num));
    return res;
}

static PyObject* Stat_user_offset(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(CART_DIM);
    PyTuple_SetItem(res, 0, PyFloat_FromDouble(s->status.task.robotUserOffset.tran.x));
    PyTuple_SetItem(res, 1, PyFloat_FromDouble(s->status.task.robotUserOffset.tran.y));
    PyTuple_SetItem(res, 2, PyFloat_FromDouble(s->status.task.robotUserOffset.tran.z));
    PyTuple_SetItem(res, 3, PyFloat_FromDouble(s->status.task.robotUserOffset.a));
    PyTuple_SetItem(res, 4, PyFloat_FromDouble(s->status.task.robotUserOffset.b));
    PyTuple_SetItem(res, 5, PyFloat_FromDouble(s->status.task.robotUserOffset.c));
    return res;
}

static int get_ana_chn_enum(int ana_chn_config)
{
    switch (ana_chn_config)
    {
    case 10:
        return 1;
    case 9:
        return 2;
    case 6:
        return 3;
    case 5:
        return 4;
    default:
        return 0;
    }
    return 0;
}

static PyObject* Stat_scb_anachn_setting(PyStatChannel* s)
{
    if (s->status.cab_type == 2)
    {
        PyObject* res = PyTuple_New(2);
        int anaChnConfig1 = (s->status.io.scb_anachn_setting >> 4) & 0xF;
        int anaChnConfig2 = s->status.io.scb_anachn_setting & 0xF;
        PyTuple_SetItem(res, 0, PyLong_FromLong(get_ana_chn_enum(anaChnConfig1)));
        PyTuple_SetItem(res, 1, PyLong_FromLong(get_ana_chn_enum(anaChnConfig2)));
        return res;
    }
    return Py_None;
}

static PyObject* Stat_scb_digchn_setting(PyStatChannel* s)
{
    if (s->status.cab_type == 3)
    {
        PyObject* res = PyTuple_New(7);
        printf("current settings: %d\n", s->status.io.scb_digchn_setting);
        for (unsigned int i = 0; i < 7; i++) { PyTuple_SetItem(res, i, PyLong_FromLong(IsBitSet(s->status.io.scb_digchn_setting, i))); }
        return res;
    }
    return Py_None;
}

static PyObject* Stat_load_identify_stat(PyStatChannel* s)
{
    PyObject* res = PyDict_New();
    PyDict_SetItemString(res, "noLoad", short_array(s->status.motion.noloadIdentifyStat, 3));
    PyDict_SetItemString(res, "onLoad", short_array(s->status.motion.onloadIdentifyStat, 3));
    return res;
}

static PyObject* Stat_friction_identify_stat(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(1);
    PyTuple_SetItem(res, 0, PyLong_FromLong(s->status.motion.identifyfrictionStat));
    return res;
}

static PyObject* Stat_friction_identify_start_pos(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(ZUCMOT_ROBOT_MAX_JOINTS * ZUCMOT_ROBOT_MAX_JOINTS);
    for (int i = 0; i < ZUCMOT_ROBOT_MAX_JOINTS * ZUCMOT_ROBOT_MAX_JOINTS; i++)
    {
        PyTuple_SetItem(res, i, PyFloat_FromDouble(s->status.motion.identifyfrictionstartposStat[i]));
    }
    return res;
}

static PyObject* Stat_friction_identify_end_pos(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(ZUCMOT_ROBOT_MAX_JOINTS * ZUCMOT_ROBOT_MAX_JOINTS);
    for (int i = 0; i < ZUCMOT_ROBOT_MAX_JOINTS * ZUCMOT_ROBOT_MAX_JOINTS; i++)
    {
        PyTuple_SetItem(res, i, PyFloat_FromDouble(s->status.motion.identifyfrictionendposStat[i]));
    }
    return res;
}

static PyObject* Stat_backdrive_state(PyStatChannel* s) { return PyLong_FromLong(s->status.motion.backdriveStat); }

static PyObject* Stat_force_limit_value(PyStatChannel* s) { return PyLong_FromLong(s->status.motion.forcelimitvalueStat); }

static PyObject* Stat_joint_collision_sensitivity(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(ZUCMOT_ROBOT_MAX_JOINTS);
    for (int i = 0; i < ZUCMOT_ROBOT_MAX_JOINTS; i++) { PyTuple_SetItem(res, i, PyLong_FromLong(s->status.motion.jointcollisionsensitivityStat[i])); }
    return res;
}

static PyObject* Stat_joint_friction_compensate(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(s->status.motion.robot_joint_num);
    for (int i = 0; i < s->status.motion.robot_joint_num; i++) { PyTuple_SetItem(res, i, PyFloat_FromDouble(s->status.motion.jointfrictioncompensateStat[i])); }
    return res;
}

static PyObject* Stat_collision_detection_enable(PyStatChannel* s) { return PyLong_FromLong(1 - s->status.motion.collisiondetectionenableStat); }

static PyObject* Stat_dynamics_identify_stat(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(1);
    PyTuple_SetItem(res, 0, PyLong_FromLong(s->status.motion.dynamicsIdentifyStat));
    return res;
}

static PyObject* Stat_dynamics_identify_traj(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(250);
    for (int i = 0; i < 250; i++) { PyTuple_SetItem(res, i, PyFloat_FromDouble(s->status.motion.dynamicsIdentifyTrajPara[i])); }
    return res;
}

static PyObject* Stat_dynamics_identify_start_pos(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(ZUCMOT_ROBOT_MAX_JOINTS);
    for (int i = 0; i < ZUCMOT_ROBOT_MAX_JOINTS; i++) { PyTuple_SetItem(res, i, PyFloat_FromDouble(s->status.motion.dynamicsIdentifyStartPos[i])); }
    return res;
}

static PyObject* Stat_identify_traj(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(4);
    for (int i = 0; i < 4; i++)
    {
        PyObject* item = PyDict_New();
        PyDict_SetItemString(item, "startJntPos", float_array(s->status.task.payloadIdentifyTraj[i].startJntPos, ZUCMOT_ROBOT_MAX_JOINTS));
        PyDict_SetItemString(item, "endJntPos", float_array(s->status.task.payloadIdentifyTraj[i].endJntPos, ZUCMOT_ROBOT_MAX_JOINTS));
        PyTuple_SetItem(res, i, item);
    }

    return res;
}

static PyObject* Stat_uhi_data(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(3);
    PyTuple_SetItem(res, 0, PyLong_FromLong(s->status.io.uhiData.dir));
    PyTuple_SetItem(res, 1, PyLong_FromLong(s->status.io.uhiData.pulses));
    PyTuple_SetItem(res, 2, PyLong_FromLong(s->status.io.uhiData.speed));
    return res;
}

static PyObject* Stat_dh_param(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(4);
    PyTuple_SetItem(res, 0, robot_joint_val(s->status.motion.dhParam.alpha));
    PyTuple_SetItem(res, 1, robot_joint_val(s->status.motion.dhParam.a));
    PyTuple_SetItem(res, 2, robot_joint_val(s->status.motion.dhParam.d));
    PyTuple_SetItem(res, 3, robot_joint_val(s->status.motion.dhParam.joint_homeoff));
    return res;
}

// 未见调用
static PyObject* Stat_capt_status(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(8);
    for (int i = 0; i < 8; i++)
    {
        PyObject* capt = PyTuple_New(3);
        PyTuple_SetItem(capt, 0, PyLong_FromLong(s->status.motion.captureStatus[i].captStatus));
        if (s->status.motion.captureStatus[i].captStatus == 2)
        {
            PyTuple_SetItem(capt, 1, PyLong_FromLong(s->status.motion.captureStatus[i].stateType));
            if (s->status.motion.captureStatus[i].stateType == 0)
            {
                PyTuple_SetItem(capt, 2, pose(s->status.motion.captureStatus[i].captRes.cartePose));
            }
            else if (s->status.motion.captureStatus[i].stateType == 1)
            {
                PyTuple_SetItem(capt, 2, double_array(s->status.motion.captureStatus[i].captRes.jointPos, ZUCMOT_ROBOT_MAX_JOINTS));
            }
        }
        PyTuple_SetItem(res, i, capt);
    }
    return res;
}

static PyObject* Stat_auto_status(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(2);
    PyTuple_SetItem(res, 0, PyLong_FromLong(s->status.autoopsetting.onekeyenable));
    PyTuple_SetItem(res, 1, PyLong_FromLong(s->status.autoopsetting.autoprogram));
    return res;
}

static PyObject* Stat_servo_filter(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(2);
    int filterType = s->status.motion.traj.servoMtnFltParam.filterType;
    PyTuple_SetItem(res, 0, PyLong_FromLong(filterType));
    PyObject* fltParam = Py_None;
    if (filterType == 1)
    {
        fltParam = PyTuple_New(1);
        PyTuple_SetItem(fltParam, 0, PyFloat_FromDouble(s->status.motion.traj.servoMtnFltParam.lpf_cutoff_freq));
    }
    else if (filterType == 2)
    {  // nlf joint
        fltParam = PyTuple_New(3);
        PyTuple_SetItem(fltParam, 0, PyFloat_FromDouble(s->status.motion.traj.servoMtnFltParam.nlf_vr));
        PyTuple_SetItem(fltParam, 1, PyFloat_FromDouble(s->status.motion.traj.servoMtnFltParam.nlf_ar));
        PyTuple_SetItem(fltParam, 2, PyFloat_FromDouble(s->status.motion.traj.servoMtnFltParam.nlf_jr));
    }
    else if (filterType == 3)
    {  // mmf joint
        fltParam = PyTuple_New(4);
        PyTuple_SetItem(fltParam, 0, PyLong_FromLong(s->status.motion.traj.servoMtnFltParam.mmf_buf_size));
        PyTuple_SetItem(fltParam, 1, PyFloat_FromDouble(s->status.motion.traj.servoMtnFltParam.mmf_kp));
        PyTuple_SetItem(fltParam, 2, PyFloat_FromDouble(s->status.motion.traj.servoMtnFltParam.mmf_kv));
        PyTuple_SetItem(fltParam, 3, PyFloat_FromDouble(s->status.motion.traj.servoMtnFltParam.mmf_ka));
    }
    else if (filterType == 4)
    {  // nlf cart
        fltParam = PyTuple_New(6);
        PyTuple_SetItem(fltParam, 0, PyFloat_FromDouble(s->status.motion.traj.servoMtnFltParam.nlf_vp));
        PyTuple_SetItem(fltParam, 1, PyFloat_FromDouble(s->status.motion.traj.servoMtnFltParam.nlf_ap));
        PyTuple_SetItem(fltParam, 2, PyFloat_FromDouble(s->status.motion.traj.servoMtnFltParam.nlf_jp));
        PyTuple_SetItem(fltParam, 3, PyFloat_FromDouble(s->status.motion.traj.servoMtnFltParam.nlf_vr));
        PyTuple_SetItem(fltParam, 4, PyFloat_FromDouble(s->status.motion.traj.servoMtnFltParam.nlf_ar));
        PyTuple_SetItem(fltParam, 5, PyFloat_FromDouble(s->status.motion.traj.servoMtnFltParam.nlf_jr));
    }
    else if (filterType == 5)
    {  // lookahead
        fltParam = PyTuple_New(2);
        PyTuple_SetItem(fltParam, 0, PyLong_FromLong(s->status.motion.traj.servoMtnFltParam.mmf_buf_size));
        PyTuple_SetItem(fltParam, 1, PyFloat_FromDouble(s->status.motion.traj.servoMtnFltParam.mmf_kp));
    }
    else
    {
        Py_INCREF(Py_None);
    }
    PyTuple_SetItem(res, 1, fltParam);
    return res;
}

static PyObject* Stat_net_exception_handle(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(2);
    PyTuple_SetItem(res, 0, PyLong_FromLong(s->status.netExceptionHandle.motType));
    PyTuple_SetItem(res, 1, PyFloat_FromDouble(s->status.netExceptionHandle.timeLimit));
    return res;
}

static PyObject* Stat_joint_position(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(ZUCMOT_MAX_JOINTS);
    for (int i = 0; i < ZUCMOT_MAX_JOINTS; i++) { PyTuple_SetItem(res, i, PyFloat_FromDouble(s->status.motion.joint[i].output)); }
    return res;
}

static PyObject* Stat_joint_actual_position(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(ZUCMOT_MAX_JOINTS);
    for (int i = 0; i < ZUCMOT_MAX_JOINTS; i++) { PyTuple_SetItem(res, i, PyFloat_FromDouble(s->status.motion.joint[i].input)); }
    return res;
}

static PyObject* Stat_pose_rotation_axis(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(3);
    for (int i = 0; i < 3; i++) { PyTuple_SetItem(res, i, PyFloat_FromDouble(s->status.motion.traj.curr_tcp_rotation_axis[i])); }
    return res;
}

static PyObject* Stat_tio_din(PyStatChannel* s)
{
    int tio_di[8] = {0};
    for (int i = 0; i < 8; i++) { tio_di[i] = (s->status.tio[0].tioStatus.DI_buffer & (1 << i)) > 0 ? 1 : 0; }
    return int_array(tio_di, 8);
}

static PyObject* Stat_tio_dout(PyStatChannel* s)
{
    int tio_do[8] = {0};
    for (int i = 0; i < 8; i++) { tio_do[i] = (s->status.tio[0].tioStatus.DO_buffer & (1 << i)) > 0 ? 1 : 0; }
    return int_array(tio_do, 8);
}

static PyObject* Stat_tio_ain(PyStatChannel* s) { return double_array(s->status.tio[0].tioStatus.AI, 4); }

static PyObject* Stat_tio_aout(PyStatChannel* s) { return double_array(s->status.tio[0].tioStatus.AO, 4); }

static PyObject* Stat_tio_uikey(PyStatChannel* s)
{
    int tio_uiKey[3] = {0};
    tio_uiKey[0] = s->status.tio[0].tioStatus.UIKey_free;
    tio_uiKey[1] = s->status.tio[0].tioStatus.UIKey_point;
    tio_uiKey[2] = s->status.tio[0].tioStatus.UIKey_pause_resume;
    return int_array(tio_uiKey, 3);
}

static PyObject* Stat_tio_version(PyStatChannel* s) { return PyLong_FromLong(s->status.tio[0].tioStatus.tio_version); }

static PyObject* Stat_tio_vout_cfg(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(2);
    PyTuple_SetItem(res, 0, PyLong_FromLong(s->status.tio[0].tioConfig.voutEna));
    PyTuple_SetItem(res, 1, PyLong_FromLong(s->status.tio[0].tioConfig.voutVol));
    return res;
}

static PyObject* Stat_tio_pin_cfg(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(3);
    PyTuple_SetItem(res, 0, PyLong_FromLong(s->status.tio[0].tioConfig.pinCfg.diCfg));
    PyTuple_SetItem(res, 1, PyLong_FromLong(s->status.tio[0].tioConfig.pinCfg.doCfg));
    PyTuple_SetItem(res, 2, PyLong_FromLong(s->status.tio[0].tioConfig.pinCfg.aiCfg));
    return res;
}

static PyObject* Stat_tio_rschn_cfg(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(2);
    for (int i = 0; i < 2; i++)
    {
        PyObject* rsCfg = PyTuple_New(2);
        PyObject* rscomm = PyTuple_New(5);
        PyTuple_SetItem(rscomm, 0, PyLong_FromLong(s->status.tio[0].tioConfig.rsChnCfg[i].rtuComm.slaveId));
        PyTuple_SetItem(rscomm, 1, PyLong_FromLong(s->status.tio[0].tioConfig.rsChnCfg[i].rtuComm.baudrate));
        PyTuple_SetItem(rscomm, 2, PyLong_FromLong(s->status.tio[0].tioConfig.rsChnCfg[i].rtuComm.databits));
        PyTuple_SetItem(rscomm, 3, PyLong_FromLong(s->status.tio[0].tioConfig.rsChnCfg[i].rtuComm.stopbits));
        PyTuple_SetItem(rscomm, 4, PyLong_FromLong(s->status.tio[0].tioConfig.rsChnCfg[i].rtuComm.parity));
        PyTuple_SetItem(rsCfg, 0, PyLong_FromLong(s->status.tio[0].tioConfig.rsChnCfg[i].mode));
        PyTuple_SetItem(rsCfg, 1, rscomm);
        PyTuple_SetItem(res, i, rsCfg);
    }
    return res;
}

static PyObject* Stat_tio_rs_signals(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(MAX_TIO_SIG_NUM);
    for (int i = 0; i < MAX_TIO_SIG_NUM; i++)
    {
        PyObject* sigObject = PyTuple_New(6);  // name, type, address, value, period
        PyTuple_SetItem(sigObject, 0, PyUnicode_FromString(s->status.tio[0].gripperState[i].sigName));
        PyTuple_SetItem(sigObject, 1, PyLong_FromLong(s->status.tio[0].gripperState[i].chnId));
        PyTuple_SetItem(sigObject, 2, PyLong_FromLong(s->status.tio[0].gripperState[i].type));
        PyTuple_SetItem(sigObject, 3, PyLong_FromLong(s->status.tio[0].gripperState[i].addr));
        PyTuple_SetItem(sigObject, 4, PyLong_FromLong(s->status.tio[0].gripperState[i].value));
        PyTuple_SetItem(sigObject, 5, PyFloat_FromDouble(s->status.tio[0].gripperState[i].freq));
        PyTuple_SetItem(res, i, sigObject);
    }
    return res;
}

static PyObject* Stat_cab_di_type(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(2);
    PyTuple_SET_ITEM(res, 0, PyLong_FromLong(s->status.io.di_type_pin_g1));
    PyTuple_SET_ITEM(res, 1, PyLong_FromLong(s->status.io.di_type_pin_g2));
    return res;
}

static PyObject* Stat_cab_do_type(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(2);
    PyTuple_SET_ITEM(res, 0, PyLong_FromLong(s->status.io.do_type_pin_g1));
    PyTuple_SET_ITEM(res, 1, PyLong_FromLong(s->status.io.do_type_pin_g2));
    return res;
}

static PyObject* Stat_cab_io_type(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(4);
    PyTuple_SET_ITEM(res, 0, PyLong_FromLong(s->status.io.di_type_pin_g1));
    PyTuple_SET_ITEM(res, 1, PyLong_FromLong(s->status.io.di_type_pin_g2));
    PyTuple_SET_ITEM(res, 2, PyLong_FromLong(s->status.io.do_type_pin_g1));
    PyTuple_SET_ITEM(res, 3, PyLong_FromLong(s->status.io.do_type_pin_g2));
    return res;
}

static PyObject* Stat_grpc_errcode(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(4);
    PyTuple_SET_ITEM(res, 0, PyLong_FromLong(s->status.grpc_errtype));
    PyTuple_SET_ITEM(res, 1, PyLong_FromLong(s->status.grpc_errcode));

    PyObject* string = Py_BuildValue("s", s->status.grpc_errmsg);
    PyTuple_SET_ITEM(res, 2, string);
    PyTuple_SET_ITEM(res, 3, PyLong_FromLong(s->status.repeatflag));

    return res;
}

static PyObject* Stat_drag_dead_zone(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(CART_DIM);
    for (int i = 0; i < CART_DIM; i++) { PyTuple_SetItem(res, i, PyFloat_FromDouble(s->status.motion.drag_dead_zone[i])); }
    return res;
}

static PyObject* Stat_task_call_stack(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(4);
    for (int i = 0; i < 4; i++)
    {
        PyObject* call = PyDict_New();
        PyDict_SetItemString(call, "file", PyUnicode_FromString(s->status.task.callStack[i].file));
        PyDict_SetItemString(call, "line", PyLong_FromLong(s->status.task.callStack[i].executingLine));
        PyTuple_SetItem(res, i, call);
    }
    return res;
}

static PyObject* Stat_limit(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(ZUCMOT_MAX_JOINTS);
    for (int i = 0; i < ZUCMOT_MAX_JOINTS; i++)
    {
        int v = 0;
        if (s->status.motion.joint[i].minHardLimit)
            v |= 1;
        if (s->status.motion.joint[i].maxHardLimit)
            v |= 2;
        if (s->status.motion.joint[i].minSoftLimit)
            v |= 4;
        if (s->status.motion.joint[i].maxSoftLimit)
            v |= 8;
        PyTuple_SET_ITEM(res, i, PyLong_FromLong(v));
    }
    return res;
}

static PyObject* Stat_homed(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(ZUCMOT_MAX_JOINTS);
    for (int i = 0; i < ZUCMOT_MAX_JOINTS; i++) { PyTuple_SET_ITEM(res, i, PyLong_FromLong(s->status.motion.joint[i].homed)); }
    return res;
}

static PyObject* Stat_din(PyStatChannel* s)
{
    static int dinNum = 0;
    if (dinNum == 0)
    {
        dinNum = ZUCMOT_ZLAN_DIO_NUM + ZUCMOT_MAX_MODBUS_DIO + ZUCMOT_MAX_PNDev_DIO;
        if (s->status.cab_type == 2)
        {
            dinNum = ZUCMOT_SCB_USER_DIO_NUM + ZUCMOT_MAX_MODBUS_DIO + ZUCMOT_MAX_PNDev_DIO;
        }
        else if (s->status.cab_type == 3)
        {
            dinNum = ZUCMOT_MINI_USER_DIO_NUM + ZUCMOT_MAX_MODBUS_DIO + ZUCMOT_MAX_PNDev_DIO;
        }
    }
    return int_array(s->status.io.synch_di, dinNum);
}

static PyObject* Stat_dout(PyStatChannel* s)
{
    static int doutNum = 0;
    if (doutNum == 0)
    {
        doutNum = ZUCMOT_ZLAN_DIO_NUM + ZUCMOT_MAX_MODBUS_DIO + ZUCMOT_MAX_PNDev_DIO;
        if (s->status.cab_type == 2)
        {
            doutNum = ZUCMOT_SCB_USER_DIO_NUM + ZUCMOT_MAX_MODBUS_DIO + ZUCMOT_MAX_PNDev_DIO;
        }
        else if (s->status.cab_type == 3)
        {
            doutNum = ZUCMOT_MINI_USER_DIO_NUM + ZUCMOT_MAX_MODBUS_DIO + ZUCMOT_MAX_PNDev_DIO;
        }
    }
    return int_array(s->status.io.synch_do, doutNum);
}

static PyObject* Stat_cab_din(PyStatChannel* s)
{
    static int dinNum = ZUCMOT_MAX_MODBUS_DIO;
    dinNum = ZUCMOT_ZLAN_DIO_NUM;
    if (s->status.cab_type == 2)
    {
        dinNum = ZUCMOT_SCB_USER_DIO_NUM;
    }
    else if (s->status.cab_type == 3)
    {
        dinNum = ZUCMOT_MINI_USER_DIO_NUM;
    }
    return int_array(s->status.io.synch_di, dinNum);
}

static PyObject* Stat_mb_slave_din(PyStatChannel* s)
{
    static int dinNum = ZUCMOT_MAX_MODBUS_DIO;
    return int_array(s->status.io.synch_mb_slave_di, dinNum);
}

static PyObject* Stat_pn_dev_din(PyStatChannel* s)
{
    static int dinNum = ZUCMOT_MAX_PNDev_DIO;
    return int_array(s->status.io.synch_pn_dev_di, dinNum);
}

static PyObject* Stat_eip_adpt_din(PyStatChannel* s)
{
    static int dinNum = 0;
    if (s->status.io.eip_mode)
    {
        dinNum = s->status.io.eip_di_num;
        return int_eip_array(s->status.io.synch_eip_in, dinNum);
    }
    else
    {
        dinNum = ZUCMOT_MAX_EIP_DIO;
        return int_array(s->status.io.synch_eip_adpt_di, dinNum);
    }
}

static PyObject* Stat_cab_dout(PyStatChannel* s)
{
    static int doutNum = 0;
    doutNum = ZUCMOT_ZLAN_DIO_NUM;
    if (s->status.cab_type == 2)
    {
        doutNum = ZUCMOT_SCB_USER_DIO_NUM;
    }
    else if (s->status.cab_type == 3)
    {
        doutNum = ZUCMOT_MINI_USER_DIO_NUM;
    }
    return int_array(s->status.io.synch_do, doutNum);
}

static PyObject* Stat_mb_slave_dout(PyStatChannel* s)
{
    static int doutNum = ZUCMOT_MAX_MODBUS_DIO;
    return int_array(s->status.io.synch_mb_slave_do, doutNum);
}

static PyObject* Stat_pn_dev_dout(PyStatChannel* s)
{
    static int doutNum = ZUCMOT_MAX_PNDev_DIO;
    return int_array(s->status.io.synch_pn_dev_do, doutNum);
}

static PyObject* Stat_eip_adpt_dout(PyStatChannel* s)
{
    static int doutNum = 0;
    if (s->status.io.eip_mode)
    {
        doutNum = s->status.io.eip_do_num;
        return int_eip_array(s->status.io.synch_eip_out, doutNum);
    }
    else
    {
        doutNum = ZUCMOT_MAX_EIP_DIO;
        return int_array(s->status.io.synch_eip_adpt_do, doutNum);
    }
}

static PyObject* Stat_cab_ain(PyStatChannel* s)
{
    static int ainNum = 0;
    ainNum = ZUCMOT_ZLAN_AI_NUM;

    if (s->status.cab_type == 2)
    {
        ainNum = ZUCMOT_SCB_USER_AIO_NUM;
    }
    else if (s->status.cab_type == 3)
    {
        ainNum = ZUCMOT_MINI_USER_AIO_NUM;
    }
    return double_array(s->status.io.analog_input, ainNum);
}

static PyObject* Stat_mb_slave_ain(PyStatChannel* s)
{
    static int ainNum = ZUCMOT_MAX_MODBUS_AIO_NUM;
    return double_array(s->status.io.analog_mb_slave_input, ainNum);
}

static PyObject* Stat_pn_dev_ain(PyStatChannel* s)
{
    static int ainNum = ZUCMOT_PNDev_INT_AIO_NUM + ZUCMOT_PNDev_FLOAT_AIO_NUM;
    return double_array(s->status.io.analog_pn_dev_input, ainNum);
}

static PyObject* Stat_eip_adpt_ain(PyStatChannel* s)
{
    static int ainNum = 0;
    if (s->status.io.eip_mode)
    {
        ainNum = s->status.io.eip_ai_int_num + s->status.io.eip_ai_float_num;
        static int num = s->status.io.eip_di_num / 8;  //DI和DO数量必须为8的n次方。
        return double_eip_array(s->status.io.synch_eip_in + num, s->status.io.eip_ai_int_num, ainNum);
    }
    else
    {
        ainNum = ZUCMOT_EIP_INT_AIO_NUM + ZUCMOT_EIP_FLOAT_AIO_NUM;
        return double_array(s->status.io.analog_eip_adpt_input, ainNum);
    }
}

static PyObject* Stat_cab_aout(PyStatChannel* s)
{
    static int aoutNum = 0;
    aoutNum = ZUCMOT_ZLAN_AO_NUM;
    if (s->status.cab_type == 2)
    {
        aoutNum = ZUCMOT_SCB_USER_AIO_NUM;
    }
    else if (s->status.cab_type == 3)
    {
        aoutNum = ZUCMOT_MINI_USER_AIO_NUM;
    }
    return double_array(s->status.io.analog_output, aoutNum);
}

static PyObject* Stat_mb_slave_aout(PyStatChannel* s)
{
    static int aoutNum = ZUCMOT_MAX_MODBUS_AIO_NUM;
    return double_array(s->status.io.analog_mb_slave_output, aoutNum);
}

static PyObject* Stat_pn_dev_aout(PyStatChannel* s)
{
    static int aoutNum = ZUCMOT_PNDev_INT_AIO_NUM + ZUCMOT_PNDev_FLOAT_AIO_NUM;
    return double_array(s->status.io.analog_pn_dev_output, aoutNum);
}

static PyObject* Stat_eip_adpt_aout(PyStatChannel* s)
{
    static int aoutNum = 0;
    if (s->status.io.eip_mode)
    {
        aoutNum = s->status.io.eip_ao_int_num + s->status.io.eip_ao_float_num;
        int num = s->status.io.eip_do_num / 8;
        return double_eip_array(s->status.io.synch_eip_out + num, s->status.io.eip_ao_int_num, aoutNum);
    }
    else
    {
        aoutNum = ZUCMOT_EIP_INT_AIO_NUM + ZUCMOT_EIP_FLOAT_AIO_NUM;
        return double_array(s->status.io.analog_eip_adpt_output, aoutNum);
    }
}

static PyObject* Stat_ain(PyStatChannel* s)
{
    static int ainNum = 0;
    if (ainNum == 0)
    {
        ainNum = ZUCMOT_ZLAN_AI_NUM + ZUCMOT_MAX_MODBUS_AIO_NUM + ZUCMOT_PNDev_INT_AIO_NUM + ZUCMOT_PNDev_FLOAT_AIO_NUM;
        if (s->status.cab_type == 2)
        {
            ainNum = ZUCMOT_SCB_USER_AIO_NUM + ZUCMOT_MAX_MODBUS_AIO_NUM + ZUCMOT_PNDev_INT_AIO_NUM + ZUCMOT_PNDev_FLOAT_AIO_NUM;
        }
        else if (s->status.cab_type == 3)
        {
            ainNum = ZUCMOT_MINI_USER_AIO_NUM + ZUCMOT_MAX_MODBUS_AIO_NUM + ZUCMOT_PNDev_INT_AIO_NUM + ZUCMOT_PNDev_FLOAT_AIO_NUM;
        }
        printf("cab_type = %d, ainNum = %d\n", s->status.cab_type, ainNum);
    }
    return double_array(s->status.io.analog_input, ainNum);
}

static PyObject* Stat_aout(PyStatChannel* s)
{
    static int aoutNum = 0;
    if (aoutNum == 0)
    {
        aoutNum = ZUCMOT_ZLAN_AO_NUM + ZUCMOT_MAX_MODBUS_AIO_NUM + ZUCMOT_PNDev_INT_AIO_NUM + ZUCMOT_PNDev_FLOAT_AIO_NUM;
        if (s->status.cab_type == 2)
        {
            aoutNum = ZUCMOT_SCB_USER_AIO_NUM + ZUCMOT_MAX_MODBUS_AIO_NUM + ZUCMOT_PNDev_INT_AIO_NUM + ZUCMOT_PNDev_FLOAT_AIO_NUM;
        }
        else if (s->status.cab_type == 3)
        {
            aoutNum = ZUCMOT_MINI_USER_AIO_NUM + ZUCMOT_MAX_MODBUS_AIO_NUM + ZUCMOT_PNDev_INT_AIO_NUM + ZUCMOT_PNDev_FLOAT_AIO_NUM;
        }
    }
    return double_array(s->status.io.analog_output, aoutNum);
}

static void dict_add(PyObject* d, const char* name, unsigned char v)
{
    PyObject* o;
    PyDict_SetItemString(d, name, o = PyLong_FromLong(v));
    Py_XDECREF(o);
}

static void dict_add(PyObject* d, const char* name, double v)
{
    PyObject* o;
    PyDict_SetItemString(d, name, o = PyFloat_FromDouble(v));
    Py_XDECREF(o);
}

#define F(x) F2(#x, x)
#define F2(y, x) dict_add(res, y, s->status.motion.joint[jointno].x)
static PyObject* Stat_joint_one(PyStatChannel* s, int jointno)
{
    PyObject* res = PyDict_New();
    F(jointType);
    F(units);
    F(backlash);
    F2("min_position_limit", minPositionLimit);
    F2("max_position_limit", maxPositionLimit);
    F2("max_ferror", maxFerror);
    F2("min_ferror", minFerror);
    F2("ferror_current", ferrorCurrent);
    F2("ferror_highmark", ferrorHighMark);
    F(output);
    F(input);
    F(velocity);
    F(acceleration);
    F(inpos);
    F(homing);
    F(homed);
    F(fault);
    F(enabled);
    F2("min_soft_limit", minSoftLimit);
    F2("max_soft_limit", maxSoftLimit);
    F2("min_hard_limit", minHardLimit);
    F2("max_hard_limit", maxHardLimit);
    return res;
}
#undef F
#undef F2

static PyObject* Stat_joint(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(ZUCMOT_MAX_JOINTS);
    for (int i = 0; i < ZUCMOT_MAX_JOINTS; i++) { PyTuple_SetItem(res, i, Stat_joint_one(s, i)); }
    return res;
}

// #define F(x) F2(#x, x)
// #define F2(y, x) dict_add(res, y, s->status.motion.axis[axisno].x)
// static PyObject* Stat_axis_one(PyStatChannel* s, int axisno)
// {
//     PyObject* res = PyDict_New();

//     F(velocity);
//     F2("min_position_limit", minPositionLimit);
//     F2("max_position_limit", maxPositionLimit);
//     return res;
// }

// #undef F
// #undef F2

static PyObject* Stat_axis(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(ZUCMOT_MAX_AXIS);
    // for (int i = 0; i < ZUCMOT_MAX_AXIS; i++) { PyTuple_SetItem(res, i, Stat_axis_one(s, i)); }
    return res;
}

static PyObject* Stat_gravity_direction(PyStatChannel* s)
{
    PyObject* res = PyTuple_New(3);
    PyTuple_SetItem(res, 0, PyFloat_FromDouble(s->status.motion.gravity_rpy[0]));
    PyTuple_SetItem(res, 1, PyFloat_FromDouble(s->status.motion.gravity_rpy[1]));
    PyTuple_SetItem(res, 2, PyFloat_FromDouble(s->status.motion.gravity_rpy[2]));
    return res;
}

static PyObject* Stat_servo_move_enabled(PyStatChannel* s)
{
    int enabled = 0;
    if (s->status.motion.traj.mode == ZUC_TRAJ_MODE_SERVOJOP)
        enabled = 1;

    return PyLong_FromLong(enabled);
}

static PyObject* Stat_full_dh_flag(PyStatChannel* s)
{
    PyObject* res = PyList_New(1);
    PyList_SetItem(res, 0, PyLong_FromLong(s->status.motion.full_dh_com));
    return res;
}

// 在name前面拼接Stat_前缀表示函数名称
#define ZUC_STAT_GET_FUNC_NAME(name) Stat_##name

// 对指定成员变量name定义getfunc函数, 内容来源于ZucStat的成员member，其中member
// 的类型为INT, 最终定义的函数名称为Stat_ + name
#define ZUC_STAT_GET_FUNC_DEF_INT(name, member) \
    PyObject* ZUC_STAT_GET_FUNC_NAME(name)(PyStatChannel * self, void* unused) { return PyLong_FromLong(self->status.member); }

// 构建getsetlist结构体内容元素 { char* name, getter* getfunc }
#define ZUC_STAT_GETSET_DEF(name)                              \
    {                                                          \
        (char*)(#name), ((getter)ZUC_STAT_GET_FUNC_NAME(name)) \
    }

// 表示getfunc函数的声明
#define ZUC_STAT_GET_FUNC_DEF(name) PyObject* ZUC_STAT_GET_FUNC_DEF_INT(name)(PyStatChannel * self, void* unused)

// 对指定成员变量name定义getfunc函数, 内容来源于ZucStat的成员member，其中member
// 的类型为INT, 最终定义的函数名称为Stat_ + name
#define ZUC_STAT_GET_FUNC_DEF_INT(name, member) \
    PyObject* ZUC_STAT_GET_FUNC_NAME(name)(PyStatChannel * self, void* unused) { return PyLong_FromLong(self->status.member); }

// 对指定成员变量name定义getfunc函数, 内容来源于ZucStat的成员member，其中member
// 的类型为UINT, 最终定义的函数名称为Stat_ + name
#define ZUC_STAT_GET_FUNC_DEF_UINT(name, member) \
    PyObject* ZUC_STAT_GET_FUNC_NAME(name)(PyStatChannel * self, void* unused) { return PyLong_FromUnsignedLong(self->status.member); }

// 对指定成员变量name定义getfunc函数, 内容来源于ZucStat的成员member，其中member
// 的类型为STR, 最终定义的函数名称为Stat_ + name
#define ZUC_STAT_GET_FUNC_DEF_STR(name, member) \
    PyObject* ZUC_STAT_GET_FUNC_NAME(name)(PyStatChannel * self, void* unused) { return PyUnicode_FromString(self->status.member); }

// 对指定成员变量name定义getfunc函数, 内容来源于ZucStat的成员member，其中member
// 的类型为BOOL, 最终定义的函数名称为Stat_ + name
#define ZUC_STAT_GET_FUNC_DEF_BOOL(name, member) \
    PyObject* ZUC_STAT_GET_FUNC_NAME(name)(PyStatChannel * self, void* unused) { return PyBool_FromLong(self->status.member); }

// 对指定成员变量name定义getfunc函数, 内容来源于ZucStat的成员member，其中member
// 的类型为DOUBLE, 最终定义的函数名称为Stat_ + name
#define ZUC_STAT_GET_FUNC_DEF_DOUBLE(name, member) \
    PyObject* ZUC_STAT_GET_FUNC_NAME(name)(PyStatChannel * self, void* unused) { return PyFloat_FromDouble(self->status.member); }

// 简单的get函数直接用宏展开实现
ZUC_STAT_GET_FUNC_DEF_INT(robot_joint_num, motion.robot_joint_num)
// {(char*)"echo_serial_number", T_INT, O(echo_serial_number), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(echo_serial_number, echo_serial_number)
// {(char*)"state", T_INT, O(status), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(status, status)
// {(char*)"robot_name", T_STRING_INPLACE, O(robotName), READONLY},
ZUC_STAT_GET_FUNC_DEF_STR(robot_name, robotName)
// {(char*)"profinet_state", T_INT, O(motion.profinet_state), READONLY, (char*)"Profinet state."},
ZUC_STAT_GET_FUNC_DEF_INT(profinet_state, io.profinet_state)
// {(char*)"appConnectionStatus", T_INT, O(appConnectionStatus), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(app_connection_status, appConnectionStatus)
// {(char*)"operation_mode_option", T_INT, O(operation_mode_option), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(operation_mode_option, operation_mode_option)
// {(char*)"eip_state", T_INT, O(motion.eip_state), READONLY, (char*)"EthernetIP state."},
ZUC_STAT_GET_FUNC_DEF_INT(eip_state, io.eip_state)
// // {(char*)"auto_op_setting", T_INT, O(auto_op_setting), READONLY},
// // {(char*)"auto_enable", T_INT, O(autoopsetting.onekeyenable), READONLY},
// // {(char*)"auto_program", T_INT, O(autoopsetting.autoprogram), READONLY},
// {(char*)"task_mode", T_INT, O(task.mode), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(task_mode, task.mode)
// {(char*)"task_state", T_INT, O(task.state), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(task_state, task.state)
// {(char*)"exec_state", T_INT, O(task.execState), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(task_exec_state, task.execState)
// {(char*)"is_stepping_mode", T_INT, O(isSteppingMode), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(is_stepping_mode, isSteppingMode)
// {(char*)"stepping_state", T_INT, O(steppingState), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(stepping_state, steppingState)
// {(char*)"interp_state", T_INT, O(task.interpState), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(interp_state, task.interpState)
// {(char*)"call_level", T_INT, O(task.callLevel), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(task_call_level, task.callLevel)
// {(char*)"read_line", T_INT, O(task.readLine), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(task_read_line, task.readLine)
// {(char*)"motion_line", T_INT, O(task.motionLine), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(task_motion_line, task.motionLine)
// {(char*)"current_line", T_INT, O(task.currentLine), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(task_current_line, task.currentLine)
// {(char*)"sleep_line", T_INT, O(task.sleepLine), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(task_sleep_line, task.sleepLine)
// {(char*)"executing_line", T_INT, O(task.executingLine), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(task_executing_line, task.executingLine)
// {(char*)"err_add_line", T_INT, O(task.errAddLine), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(task_err_add_line, task.errAddLine)
// {(char*)"file", T_STRING_INPLACE, O(task.file), READONLY},
ZUC_STAT_GET_FUNC_DEF_STR(file, task.file)
// {(char*)"command", T_STRING_INPLACE, O(task.command), READONLY},
ZUC_STAT_GET_FUNC_DEF_STR(task_command, task.command)
// {(char*)"program_units", T_INT, O(task.programUnits), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(task_program_units, task.programUnits)
// {(char*)"interpreter_errcode", T_INT, O(task.interpreter_errcode), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(task_interp_errcode, task.interpreter_errcode)
// {(char*)"optional_stop", T_BOOL, O(task.optional_stop_state), READONLY},
ZUC_STAT_GET_FUNC_DEF_BOOL(task_optional_stop_state, task.optional_stop_state)
// {(char*)"block_delete", T_BOOL, O(task.block_delete_state), READONLY},
ZUC_STAT_GET_FUNC_DEF_BOOL(task_block_del_state, task.block_delete_state)
// {(char*)"task_paused", T_INT, O(task.task_paused), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(task_paused, task.task_paused)
// {(char*)"input_timeout", T_BOOL, O(task.input_timeout), READONLY},
ZUC_STAT_GET_FUNC_DEF_BOOL(task_input_timeout, task.input_timeout)
// {(char*)"delay_left", T_DOUBLE, O(task.delayLeft), READONLY},
ZUC_STAT_GET_FUNC_DEF_DOUBLE(task_delay_left, task.delayLeft)
// {(char*)"queued_mdi_commands", T_INT, O(task.queuedMDIcommands), READONLY, (char*)"Number of MDI commands queued waiting to run."},
ZUC_STAT_GET_FUNC_DEF_INT(task_queued_MDI_commands, task.queuedMDIcommands)
// {(char*)"is_diag_collecting", T_BOOL, O(isDiagCollecting), READONLY},
ZUC_STAT_GET_FUNC_DEF_BOOL(is_diag_collecting, isDiagCollecting)
// motion
// {(char*)"linear_units", T_DOUBLE, O(motion.traj.linearUnits), READONLY},
ZUC_STAT_GET_FUNC_DEF_DOUBLE(traj_linear_units, motion.traj.linearUnits)
// {(char*)"angular_units", T_DOUBLE, O(motion.traj.angularUnits), READONLY},
ZUC_STAT_GET_FUNC_DEF_DOUBLE(traj_angular_units, motion.traj.angularUnits)
// {(char*)"cycle_time", T_DOUBLE, O(motion.traj.cycleTime), READONLY},
ZUC_STAT_GET_FUNC_DEF_DOUBLE(traj_cycle_time, motion.traj.cycleTime)
// {(char*)"joints", T_INT, O(motion.traj.joints), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(traj_joints, motion.traj.joints)
// {(char*)"axis_mask", T_INT, O(motion.traj.axis_mask), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(traj_axis_mask, motion.traj.axis_mask)
// {(char*)"motion_mode", T_INT, O(motion.traj.mode), READONLY, (char*)"Current mode of MC: TRAJ_MODE_FREE, TRAJ_MODE_COORD, or TRAJ_MODE_TELEOP."},
ZUC_STAT_GET_FUNC_DEF_INT(motion_mode, motion.traj.mode)
// {(char*)"inpos", T_BOOL, O(motion.traj.inpos), READONLY},
ZUC_STAT_GET_FUNC_DEF_BOOL(inpos, motion.traj.inpos)
// {(char*)"queue", T_INT, O(motion.traj.queue), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(traj_queue, motion.traj.queue)
// {(char*)"active_queue", T_INT, O(motion.traj.activeQueue), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(traj_active_queue, motion.traj.activeQueue)
// {(char*)"queue_full", T_BOOL, O(motion.traj.queueFull), READONLY},
ZUC_STAT_GET_FUNC_DEF_BOOL(traj_queue_full, motion.traj.queueFull)
// {(char*)"id", T_INT, O(motion.traj.id), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(traj_id, motion.traj.id)
// {(char*)"paused", T_BOOL, O(motion.traj.paused), READONLY},
ZUC_STAT_GET_FUNC_DEF_BOOL(traj_paused, motion.traj.paused)
// {(char*)"feedrate", T_DOUBLE, O(motion.traj.scale), READONLY},
ZUC_STAT_GET_FUNC_DEF_DOUBLE(traj_feedrate, motion.traj.scale)
// {(char*)"rapidrate", T_DOUBLE, O(motion.traj.rapid_scale), READONLY},
ZUC_STAT_GET_FUNC_DEF_DOUBLE(traj_rapidrate, motion.traj.rapid_scale)

// {(char*)"velocity", T_DOUBLE, O(motion.traj.velocity), READONLY},
ZUC_STAT_GET_FUNC_DEF_DOUBLE(traj_velocity, motion.traj.velocity)
// {(char*)"acceleration", T_DOUBLE, O(motion.traj.acceleration), READONLY},
ZUC_STAT_GET_FUNC_DEF_DOUBLE(traj_acceleration, motion.traj.acceleration)
// {(char*)"max_velocity", T_DOUBLE, O(motion.traj.maxVelocity), READONLY},
ZUC_STAT_GET_FUNC_DEF_DOUBLE(traj_max_velocity, motion.traj.maxVelocity)
// {(char*)"max_acceleration", T_DOUBLE, O(motion.traj.maxAcceleration), READONLY},
ZUC_STAT_GET_FUNC_DEF_DOUBLE(traj_max_acceleration, motion.traj.maxAcceleration)
// {(char*)"kinematics_type", T_INT, O(motion.traj.kinematics_type), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(traj_kinematics_type, motion.traj.kinematics_type)
// {(char*)"motion_type",
//  T_INT,
//  O(motion.traj.motion_type),
//  READONLY,
//  (char*)"The type of the currently executing motion (one of MOTION_TYPE_TRAVERSE,\n"
//         "MOTION_TYPE_FEED, MOTION_TYPE_ARC, MOTION_TYPE_TOOLCHANGE,\n"
//         "MOTION_TYPE_PROBING, or MOTION_TYPE_INDEXROTARY), or 0 if no motion is\n"
//         "currently taking place."},
ZUC_STAT_GET_FUNC_DEF_INT(motion_type, motion.traj.motion_type)
// {(char*)"distance_to_go", T_DOUBLE, O(motion.traj.distance_to_go), READONLY},
ZUC_STAT_GET_FUNC_DEF_DOUBLE(distance_to_go, motion.traj.distance_to_go)
// {(char*)"current_vel", T_DOUBLE, O(motion.traj.current_vel), READONLY},
ZUC_STAT_GET_FUNC_DEF_DOUBLE(current_vel, motion.traj.current_vel)
// {(char*)"curr_tcp_trans_vel", T_DOUBLE, O(motion.traj.curr_tcp_trans_vel), READONLY},
ZUC_STAT_GET_FUNC_DEF_DOUBLE(curr_tcp_trans_vel, motion.traj.curr_tcp_trans_vel)
// {(char*)"curr_tcp_angular_vel", T_DOUBLE, O(motion.traj.curr_tcp_angular_vel), READONLY},
ZUC_STAT_GET_FUNC_DEF_DOUBLE(curr_tcp_angular_vel, motion.traj.curr_tcp_angular_vel)
// {(char*)"curr_elbow_vel", T_DOUBLE, O(motion.traj.curr_elbow_vel), READONLY},
ZUC_STAT_GET_FUNC_DEF_DOUBLE(curr_elbow_vel, motion.traj.curr_elbow_vel)
// {(char*)"vel_tcp_angular", T_DOUBLE, O(motion.traj.vel_tcp_angular), READONLY},
ZUC_STAT_GET_FUNC_DEF_DOUBLE(vel_tcp_angular, motion.traj.vel_tcp_angular)
// {(char*)"acc_tcp_linear", T_DOUBLE, O(motion.traj.acc_tcp_linear), READONLY},
ZUC_STAT_GET_FUNC_DEF_DOUBLE(acc_tcp_linear, motion.traj.acc_tcp_linear)
// {(char*)"acc_tcp_angular", T_DOUBLE, O(motion.traj.acc_tcp_angular), READONLY},
ZUC_STAT_GET_FUNC_DEF_DOUBLE(acc_tcp_angular, motion.traj.acc_tcp_angular)
// {(char*)"feed_override_enabled", T_BOOL, O(motion.traj.feed_override_enabled), READONLY},
ZUC_STAT_GET_FUNC_DEF_BOOL(feed_override_enabled, motion.traj.feed_override_enabled)
// /*property interface for app clent*/
// {(char*)"enabled", T_BOOL, O(motion.traj.enabled), READONLY},
ZUC_STAT_GET_FUNC_DEF_BOOL(enabled, motion.traj.enabled)
// {(char*)"is_being_enabled", T_BOOL, O(motion.traj.is_being_enabled), READONLY},
ZUC_STAT_GET_FUNC_DEF_BOOL(is_being_enabled, motion.traj.is_being_enabled)
// {(char*)"cat1StopProgramPaused", T_BOOL, O(motion.category_one_stop_program_pause), READONLY},
ZUC_STAT_GET_FUNC_DEF_BOOL(cat1_stop_program_paused, motion.category_one_stop_program_pause)
// {(char*)"powered_on", T_INT, O(motion.powered_on), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(powered_on, motion.powered_on)
// {(char*)"is_powering_on", T_BOOL, O(motion.is_powering_on), READONLY},
ZUC_STAT_GET_FUNC_DEF_BOOL(is_powering_on, motion.is_powering_on)
// {(char*)"protective_stop", T_INT, O(motion.protective_stop), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(protective_stop, motion.protective_stop)
// {(char*)"emergency_stop", T_INT, O(motion.emergency_stop), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(emergency_stop, motion.emergency_stop)
// {(char*)"on_soft_limit", T_INT, O(motion.on_soft_limit), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(on_soft_limit, motion.on_soft_limit)
// {(char*)"next_to_limit", T_INT, O(motion.next_to_limit), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(next_to_limit, motion.next_to_limit)
// {(char*)"percentage_mode_level", T_INT, O(motion.percentage_mode_level), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(percentage_mode_level, motion.percentage_mode_level)
// {(char*)"reduce_mode", T_INT, O(motion.is_reduce_mode), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(reduce_mode, motion.is_reduce_mode)
// {(char*)"next_to_limit", T_INT, O(motion.next_to_limit), READONLY},
// ZUC_STAT_GETSET_DEF(next_to_limit),
// {(char*)"servo_upGrade_percentage_total", T_INT, O(motion.servo_upGrade_percentage_total), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(servo_upGrade_percentage_total, servo_upGrade_percentage_total)
// {(char*)"servo_upGrade_percentage_axis", T_INT, O(motion.servo_upGrade_percentage_axis), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(servo_upGrade_percentage_axis, servo_upGrade_percentage_axis)
// {(char*)"servo_version", T_INT, O(motion.servo.servo_version), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(servo_version, motion.joint[0].servo_version)
// {(char*)"first_poweron_date", T_INT, O(motion.servo.first_poweron_date), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(first_poweron_date, motion.joint[0].first_poweron_date)
// {(char*)"clsn_sensitivity", T_INT, O(motion.servo.clsn_sensitivity), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(clsn_sensitivity, motion.joint[0].clsn_sensitivity)
// {(char*)"scb_br_start_vol", T_INT, O(motion.scb_br_start_vol), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(scb_br_start_vol, scb_br_start_vol)
// {(char*)"robot_serial_num", T_INT, O(motion.robot_serial_num), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(robot_serial_num, motion.robot_serial_num)
// {(char*)"debug", T_INT, O(debug), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(debug, debug)
// {(char*)"stepping_wait", T_INT, O(steppingWait), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(stepping_wait, steppingWait)
// {(char*)"cab_type", T_INT, O(cab_type), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(cab_type, cab_type)
// {(char*)"curCabVoltage", T_INT, O(motion.curCabVoltage), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(cur_cab_voltage, curCabVoltage)
// {(char*)"safetyCRC", T_UINT, O(motion.safetyCRC), READONLY},
ZUC_STAT_GET_FUNC_DEF_UINT(safety_crc, motion.safetyCRC)
// {(char*)"homeVel", T_DOUBLE, O(homeVel), READONLY},
ZUC_STAT_GET_FUNC_DEF_DOUBLE(home_vel, motion.homeVel)
// {(char*)"sim_mode", T_INT, O(currSimMode), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(sim_mode, currSimMode)
// {(char*)"tio_lamp_color", T_BYTE, O(tio[0].Lamp_color), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(tio_lamp_color, tio[0].tioStatus.Lamp_color)
// {(char*)"robot_real_power", T_DOUBLE, O(motion.robot_real_power), READONLY},
ZUC_STAT_GET_FUNC_DEF_DOUBLE(robot_real_power, motion.robot_real_power)
// {(char*)"robot_real_momentum", T_DOUBLE, O(motion.robot_real_momentum), READONLY},
ZUC_STAT_GET_FUNC_DEF_DOUBLE(robot_real_momentum, motion.robot_real_momentum)
//{(char*)"torque_control_enable", T_INT, O(motion.torque_control_enable), READONLY},
ZUC_STAT_GET_FUNC_DEF_INT(torque_control_enable, motion.torque_control_enable)

// 定义类Python getter/setter方法, 当前只实现了get方法，依次对于定义的成员只可取值，不可赋值
static PyGetSetDef Stat_getsetlist[] = {
    // {(char*)"actual_position", (getter)Stat_actual},
    ZUC_STAT_GETSET_DEF(actual_position),
    // {(char*)"ain", (getter)Stat_ain},
    ZUC_STAT_GETSET_DEF(ain),
    // {(char*)"aout", (getter)Stat_aout},
    ZUC_STAT_GETSET_DEF(aout),
    // {(char*)"joint", (getter)Stat_joint},
    ZUC_STAT_GETSET_DEF(joint),
    // {(char*)"axis", (getter)Stat_axis},
    // ZUC_STAT_GETSET_DEF(axis),
    // {(char*)"din", (getter)Stat_din},
    ZUC_STAT_GETSET_DEF(din),
    // {(char*)"dout", (getter)Stat_dout},
    ZUC_STAT_GETSET_DEF(dout),
    // {(char*)"cab_din", (getter)Stat_cab_din},
    ZUC_STAT_GETSET_DEF(cab_din),
    // {(char*)"mb_slave_din", (getter)Stat_mb_slave_din},
    ZUC_STAT_GETSET_DEF(mb_slave_din),
    // {(char*)"pn_dev_din", (getter)Stat_pn_dev_din},
    ZUC_STAT_GETSET_DEF(pn_dev_din),
    // {(char*)"eip_adpt_din", (getter)Stat_eip_adpt_din},
    ZUC_STAT_GETSET_DEF(eip_adpt_din),
    // {(char*)"cab_dout", (getter)Stat_cab_dout},
    ZUC_STAT_GETSET_DEF(cab_dout),
    // {(char*)"mb_slave_dout", (getter)Stat_mb_slave_dout},
    ZUC_STAT_GETSET_DEF(mb_slave_dout),
    // {(char*)"pn_dev_dout", (getter)Stat_pn_dev_dout},
    ZUC_STAT_GETSET_DEF(pn_dev_dout),
    // {(char*)"eip_adpt_dout", (getter)Stat_eip_adpt_dout},
    ZUC_STAT_GETSET_DEF(eip_adpt_dout),
    // {(char*)"cab_ain", (getter)Stat_cab_ain},
    ZUC_STAT_GETSET_DEF(cab_ain),
    // {(char*)"mb_slave_ain", (getter)Stat_mb_slave_ain},
    ZUC_STAT_GETSET_DEF(mb_slave_ain),
    // {(char*)"pn_dev_ain", (getter)Stat_pn_dev_ain},
    ZUC_STAT_GETSET_DEF(pn_dev_ain),
    // {(char*)"eip_adpt_ain", (getter)Stat_eip_adpt_ain},
    ZUC_STAT_GETSET_DEF(eip_adpt_ain),
    // {(char*)"cab_aout", (getter)Stat_cab_aout},
    ZUC_STAT_GETSET_DEF(cab_aout),
    // {(char*)"mb_slave_aout", (getter)Stat_mb_slave_aout},
    ZUC_STAT_GETSET_DEF(mb_slave_aout),
    // {(char*)"pn_dev_aout", (getter)Stat_pn_dev_aout},
    ZUC_STAT_GETSET_DEF(pn_dev_aout),
    // {(char*)"eip_adpt_aout", (getter)Stat_eip_adpt_aout},
    ZUC_STAT_GETSET_DEF(eip_adpt_aout),
    // {(char*)"tio_din", (getter)Stat_tio_din},
    ZUC_STAT_GETSET_DEF(tio_din),
    // {(char*)"tio_dout", (getter)Stat_tio_dout},
    ZUC_STAT_GETSET_DEF(tio_dout),
    // {(char*)"tio_ain", (getter)Stat_tio_ain},
    ZUC_STAT_GETSET_DEF(tio_ain),
    // {(char*)"tio_aout", (getter)Stat_tio_aout},
    ZUC_STAT_GETSET_DEF(tio_aout),
    // {(char*)"tio_uikey", (getter)Stat_tio_uikey},
    ZUC_STAT_GETSET_DEF(tio_uikey),
    // {(char*)"tio_version", (getter)Stat_tio_version},
    ZUC_STAT_GETSET_DEF(tio_version),
    // {(char*)"tio_vout_cfg", (getter)tio_vout_cfg},
    ZUC_STAT_GETSET_DEF(tio_vout_cfg),
    // {(char*)"tio_pin_cfg", (getter)tio_pin_cfg},
    ZUC_STAT_GETSET_DEF(tio_pin_cfg),
    // {(char*)"tio_rschn_cfg", (getter)tio_rschn_cfg},
    ZUC_STAT_GETSET_DEF(tio_rschn_cfg),
    // {(char*)"tio_rs_signals", (getter)Stat_tio_rs_signals},
    ZUC_STAT_GETSET_DEF(tio_rs_signals),
    // {(char*)"get_io_num", (getter)get_io_num},
    // {(char*)"homed", (getter)Stat_homed},
    ZUC_STAT_GETSET_DEF(homed),
    // {(char*)"limit", (getter)Stat_limit},
    ZUC_STAT_GETSET_DEF(limit),
    // {(char*)"position", (getter)Stat_position},
    ZUC_STAT_GETSET_DEF(position),
    // {(char*)"dtg", (getter)Stat_dtg},
    ZUC_STAT_GETSET_DEF(dtg),
    // {(char*)"joint_position", (getter)Stat_joint_position},
    ZUC_STAT_GETSET_DEF(joint_position),
    // {(char*)"joint_actual_position", (getter)Stat_joint_actual},
    ZUC_STAT_GETSET_DEF(joint_actual_position),
    // {(char*)"pose_rotation_axis", (getter)Stat_pose_rotation_axis},
    ZUC_STAT_GETSET_DEF(pose_rotation_axis),
    // {(char*)"axes", (getter)Stat_axes},
    ZUC_STAT_GETSET_DEF(axes),
    // {(char*)"tool_offset", (getter)Stat_robot_tool_offset},
    ZUC_STAT_GETSET_DEF(tool_offset),
    // {(char*)"installation_angle", (getter)Stat_installation_angle},
    ZUC_STAT_GETSET_DEF(installation_angle),
    // {(char*)"current_tool_id", (getter)Stat_current_tool_id},
    ZUC_STAT_GETSET_DEF(current_tool_id),
    // {(char*)"current_user_id", (getter)Stat_current_user_id},
    ZUC_STAT_GETSET_DEF(current_user_id),
    // {(char*)"funcdi", (getter)Stat_funcdi},
    ZUC_STAT_GETSET_DEF(funcdi),
    // {(char*)"funcdo", (getter)Stat_funcdo},
    ZUC_STAT_GETSET_DEF(funcdo),
    // {(char*)"safety_funcdi", (getter)Stat_safety_funcdi},
    ZUC_STAT_GETSET_DEF(safety_funcdi),
    // {(char*)"safety_funcdo", (getter)Stat_safety_funcdo},
    ZUC_STAT_GETSET_DEF(safety_funcdo),
    // {(char*)"payload", (getter)Stat_payload},
    ZUC_STAT_GETSET_DEF(payload),
    // {(char*)"drag_near_limit", (getter)Stat_drag_near_limit},
    ZUC_STAT_GETSET_DEF(drag_near_limit),
    // {(char*)"extio_num", (getter)Stat_extio_num},
    ZUC_STAT_GETSET_DEF(extio_num),
    // {(char*)"extio_setup", (getter)Stat_extio_setup},
    ZUC_STAT_GETSET_DEF(extio_setup),
    // {(char*)"extio_pinmap", (getter)Stat_extio_pinmap},
    ZUC_STAT_GETSET_DEF(extio_pinmap),
    // {(char*)"extio_mode", (getter)Stat_extio_mode},
    ZUC_STAT_GETSET_DEF(extio_mode),
    // {(char*)"extio_stat", (getter)Stat_extio_stat},
    ZUC_STAT_GETSET_DEF(extio_stat),
    // {(char*)"auto_work", (getter)Stat_auto_work},
    ZUC_STAT_GETSET_DEF(auto_work),
    // {(char*)"backup_setting", (getter)Stat_backup_setting},
    ZUC_STAT_GETSET_DEF(backup_setting),
    // {(char*)"slave_config", (getter)Stat_slave_config},
    ZUC_STAT_GETSET_DEF(slave_config),
    // {(char*)"servo_upGrade_percentage", (getter)Stat_servo_upgrade_percentage},
    ZUC_STAT_GETSET_DEF(servo_upGrade_percentage),
    // {(char*)"robot_model_data", (getter)Stat_robot_model_data},
    ZUC_STAT_GETSET_DEF(robot_model_data),
    // {(char*)"torqsensor", (getter)Stat_torqsensor},
    ZUC_STAT_GETSET_DEF(torqsensor),
    // {(char*)"admit_axis_opt", (getter)Stat_admit_axis_opt},
    ZUC_STAT_GETSET_DEF(admit_axis_opt),
    // {(char*)"admittance_enabled", (getter)Stat_admittance_enabled},
    ZUC_STAT_GETSET_DEF(admittance_enabled),
    // {(char*)"scb_stick_locked", (getter)Stat_scb_stick_locked},
    ZUC_STAT_GETSET_DEF(scb_stick_locked),
    // {(char*)"scb_anachn_setting", (getter)Stat_scb_anachn_setting},
    ZUC_STAT_GETSET_DEF(scb_anachn_setting),
    // {(char*)"scb_digchn_setting", (getter)Stat_scb_digchn_setting},
    ZUC_STAT_GETSET_DEF(scb_digchn_setting),
    // {(char*)"toolPayLoad", (getter)Stat_toolPayLoad},
    ZUC_STAT_GETSET_DEF(tool_payload),
    // {(char*)"torque_sensor_soft_limit", (getter)Stat_torque_sensor_soft_limit},
    ZUC_STAT_GETSET_DEF(torque_sensor_soft_limit),
    // {(char*)"admittance_ctrl_frame", (getter)Stat_admittance_ctrl_frame},
    ZUC_STAT_GETSET_DEF(admittance_ctrl_frame),
    // {(char*)"torque_sensor_filter", (getter)Stat_torque_sensor_filter},
    ZUC_STAT_GETSET_DEF(torque_sensor_filter),
    // {(char*)"torque_sensor_brand", (getter)Stat_torque_sensor_brand},
    ZUC_STAT_GETSET_DEF(torque_sensor_brand),
    // {(char*)"vel_compliant_ctrl", (getter)Stat_vel_compliant_ctrl},
    ZUC_STAT_GETSET_DEF(vel_compliant_ctrl),
    // {(char*)"compliant_Condition", (getter)Stat_compliant_Condition},
    ZUC_STAT_GETSET_DEF(compliant_condition),
    // {(char*)"admit_ctrl_config", (getter)Stat_admit_ctrl_config},
    ZUC_STAT_GETSET_DEF(admit_ctrl_config),
    // {(char*)"compliant_type_enable", (getter)Stat_compliant_type_enable},
    ZUC_STAT_GETSET_DEF(compliant_type_enable),
    // {(char*)"shrunken_pose", (getter)Stat_shrunken_pose},
    ZUC_STAT_GETSET_DEF(shrunken_pose),
    // {(char*)"stretched_pose", (getter)Stat_stretched_pose},
    ZUC_STAT_GETSET_DEF(stretched_pose),
    // {(char*)"initial_pose", (getter)Stat_initial_pose},
    ZUC_STAT_GETSET_DEF(initial_pose),
    // {(char*)"init_pose_tol", (getter)Stat_init_pose_tol},
    ZUC_STAT_GETSET_DEF(init_pose_tol),
    // {(char*)"monitor_data", (getter)Stat_monitor_data},
    ZUC_STAT_GETSET_DEF(monitor_data),
    // {(char*)"servo_data", (getter)Stat_servo_data},
    ZUC_STAT_GETSET_DEF(servo_data),
    // {(char*)"percentage_mode_level_val", (getter)Stat_percentage_mode_level_val},
    ZUC_STAT_GETSET_DEF(percentage_mode_level_val),
    // {(char*)"dh_param", (getter)Stat_dh_param},
    ZUC_STAT_GETSET_DEF(dh_param),
    // {(char*)"load_identify_stat", (getter)Stat_load_identify_stat},
    ZUC_STAT_GETSET_DEF(load_identify_stat),
    // {(char*)"user_offset", (getter)Stat_user_offset},
    ZUC_STAT_GETSET_DEF(user_offset),
    // 这一行存在重复
    // {(char*)"scb_anachn_setting", (getter)Stat_scb_anachn_setting},
    // {(char*)"identify_traj", (getter)Stat_identify_traj},
    ZUC_STAT_GETSET_DEF(identify_traj),
    // {(char*)"uhi_data", (getter)Stat_uhi_data},
    ZUC_STAT_GETSET_DEF(uhi_data),
    // {(char*)"auto_identify_tool_payload", (getter)Stat_auto_identify_tool_payload},
    // {(char*)"auto_identify_init_point", (getter)Stat_auto_identify_init_point},
    // {(char*)"capt_status", (getter)Stat_capt_status},
    ZUC_STAT_GETSET_DEF(capt_status),
    // {(char*)"auto_status", (getter)Stat_auto_status},
    ZUC_STAT_GETSET_DEF(auto_status),
    // {(char*)"servo_filter", (getter)Stat_servo_filter},
    ZUC_STAT_GETSET_DEF(servo_filter),
    // {(char*)"robot_safety", (getter)Stat_robot_safety},
    ZUC_STAT_GETSET_DEF(robot_safety),
    // {(char*)"joint_safety", (getter)Stat_joint_safety},
    ZUC_STAT_GETSET_DEF(joint_safety),
    // {(char*)"reduce_safety", (getter)Stat_reduce_safety},
    ZUC_STAT_GETSET_DEF(reduce_safety),
    // {(char*)"drag_speed_limit", (getter)Stat_drag_speed_limit},
    ZUC_STAT_GETSET_DEF(drag_speed_limit),
    // {(char*)"safe_zone", (getter)Stat_safe_zone},
    ZUC_STAT_GETSET_DEF(safe_zone),
    // {(char*)"kine_lib_version", (getter)Stat_kine_lib_version},
    ZUC_STAT_GETSET_DEF(kine_lib_version),
    // {(char*)"vrep_safe_simulation_information", (getter)Stat_Vrep_safe_simulation_information},
    ZUC_STAT_GETSET_DEF(vrep_safe_simulation_information),
    // {(char*)"elbow_pos", (getter)Stat_Carte_Elbow_Pos},
    ZUC_STAT_GETSET_DEF(elbow_pos),
    // {(char*)"step_status", (getter)Stat_step_status},
    ZUC_STAT_GETSET_DEF(step_status),
    // {(char*)"tool_offsets", (getter)Stat_robot_tool_offsets},
    ZUC_STAT_GETSET_DEF(tool_offsets),
    // {(char*)"user_offsets", (getter)Stat_robot_user_offsets},
    ZUC_STAT_GETSET_DEF(user_offsets),
    // {(char*)"net_exception_handle", (getter)Stat_net_exception_handle},
    ZUC_STAT_GETSET_DEF(net_exception_handle),
    // {(char*)"collision_option", (getter)Stat_collision_option},
    ZUC_STAT_GETSET_DEF(collision_option),
    // {(char*)"sub_thread_state", (getter)Stat_sub_thread_state},
    ZUC_STAT_GETSET_DEF(sub_thread_state),
    // {(char*)"is_robot_in_limited_status", (getter)Stat_robot_in_limited_status},
    ZUC_STAT_GETSET_DEF(is_robot_in_limited_status),
    // {(char*)"is_joint_pos_limited", (getter)Stat_is_joint_pos_limited},
    ZUC_STAT_GETSET_DEF(is_joint_pos_limited),
    // {(char*)"is_joint_vel_limited", (getter)Stat_is_joint_vel_limited},
    ZUC_STAT_GETSET_DEF(is_joint_vel_limited),
    // {(char*)"free_button_opt", (getter)Stat_free_button_opt},
    ZUC_STAT_GETSET_DEF(free_button_opt),
    // {(char*)"free_prog_button_opt", (getter)Stat_free_prog_button_opt},
    ZUC_STAT_GETSET_DEF(free_prog_button_opt),
    // {(char*)"point_button_opt", (getter)Stat_point_button_opt},
    ZUC_STAT_GETSET_DEF(point_button_opt),
    // {(char*)"cab_di_type", (getter)Stat_cab_di_type},
    ZUC_STAT_GETSET_DEF(cab_di_type),
    // {(char*)"cab_do_type", (getter)Stat_cab_do_type},
    ZUC_STAT_GETSET_DEF(cab_do_type),
    // {(char*)"cab_io_type", (getter)Stat_cab_io_type},
    ZUC_STAT_GETSET_DEF(cab_io_type),
    // {(char*)"onekeyUpgradeVerion", (getter)Stat_onekeyUpgradeVerion},
    ZUC_STAT_GETSET_DEF(onekey_upgrade_verion),
    // {(char*)"grpc_errcode", (getter)Stat_grpc_errcode},
    ZUC_STAT_GETSET_DEF(grpc_errcode),
    // {(char*)"task_call_stack", (getter)Stat_task_call_stack},
    ZUC_STAT_GETSET_DEF(task_call_stack),
    // {(char*)"position_desired", (getter)Stat_position_desired},
    ZUC_STAT_GETSET_DEF(position_desired),
    // {(char*)"position_segTarget", (getter)Stat_position_segTarget},
    ZUC_STAT_GETSET_DEF(position_seg_target),
    // {(char*)"drag_dead_zone", (getter)Stat_admittance_drag_dead_zone},
    ZUC_STAT_GETSET_DEF(drag_dead_zone),
    // {(char*)"friction_identify_start_pos", (getter)Stat_identify_friction_start_pos_stat},
    ZUC_STAT_GETSET_DEF(friction_identify_start_pos),
    // {(char*)"friction_identify_end_pos", (getter)Stat_identify_friction_end_pos_stat},
    ZUC_STAT_GETSET_DEF(friction_identify_end_pos),
    // {(char*)"friction_identify_stat", (getter)Stat_identify_friction_stat},
    ZUC_STAT_GETSET_DEF(friction_identify_stat),
    // {(char*)"dynamics_identify_stat", (getter)Stat_dynamics_identify_stat},
    ZUC_STAT_GETSET_DEF(dynamics_identify_stat),
    // {(char*)"dynamics_identify_traj", (getter)Stat_dynamics_identify_traj},
    ZUC_STAT_GETSET_DEF(dynamics_identify_traj),
    // {(char*)"dynamics_identify_start_pos", (getter)Stat_dynamics_identify_start_pos},
    ZUC_STAT_GETSET_DEF(dynamics_identify_start_pos),
    // {(char*)"backdrive_state", (getter)Stat_backdrive_stat},
    ZUC_STAT_GETSET_DEF(backdrive_state),
    // {(char*)"force_limit_value", (getter)Stat_force_limit_value_stat},
    ZUC_STAT_GETSET_DEF(force_limit_value),
    // {(char*)"joint_collision_sensitivity", (getter)Stat_joint_collision_sensitivity_stat},
    ZUC_STAT_GETSET_DEF(joint_collision_sensitivity),
    // {(char*)"joint_friction_compensate", (getter)Stat_joint_friction_compensate_stat},
    ZUC_STAT_GETSET_DEF(joint_friction_compensate),
    // {(char*)"collision_detection_enable", (getter)Stat_collision_detection_enable_stat},
    ZUC_STAT_GETSET_DEF(collision_detection_enable),
    // {(char*)"current_robot_model", (getter)Stat_current_robot_model},
    ZUC_STAT_GETSET_DEF(current_robot_model),
    // {(char*)"robot_joint_num", (getter)Stat_robot_joint_num},
    ZUC_STAT_GETSET_DEF(robot_joint_num),
    // {(char*)"echo_serial_number", T_INT, O(echo_serial_number), READONLY},
    ZUC_STAT_GETSET_DEF(echo_serial_number),
    // {(char*)"state", T_INT, O(status), READONLY},
    ZUC_STAT_GETSET_DEF(status),
    // {(char*)"robot_name", T_STRING_INPLACE, O(robotName), READONLY},
    ZUC_STAT_GETSET_DEF(robot_name),
    // {(char*)"profinet_state", T_INT, O(profinet_state), READONLY, (char*)"Profinet state."},
    ZUC_STAT_GETSET_DEF(profinet_state),
    // {(char*)"appConnectionStatus", T_INT, O(appConnectionStatus), READONLY},
    ZUC_STAT_GETSET_DEF(app_connection_status),
    // {(char*)"operation_mode_option", T_INT, O(operation_mode_option), READONLY},
    ZUC_STAT_GETSET_DEF(operation_mode_option),
    // {(char*)"eip_state", T_INT, O(motion.eip_state), READONLY, (char*)"EthernetIP state."},
    ZUC_STAT_GETSET_DEF(eip_state),
    // // {(char*)"auto_op_setting", T_INT, O(auto_op_setting), READONLY},
    // // {(char*)"auto_enable", T_INT, O(autoopsetting.onekeyenable), READONLY},
    // // {(char*)"auto_program", T_INT, O(autoopsetting.autoprogram), READONLY},
    // {(char*)"task_mode", T_INT, O(task.mode), READONLY},
    ZUC_STAT_GETSET_DEF(task_mode),
    // {(char*)"task_state", T_INT, O(task.state), READONLY},
    ZUC_STAT_GETSET_DEF(task_state),
    // {(char*)"exec_state", T_INT, O(task.execState), READONLY},
    ZUC_STAT_GETSET_DEF(task_exec_state),
    // {(char*)"is_stepping_mode", T_INT, O(isSteppingMode), READONLY},
    ZUC_STAT_GETSET_DEF(is_stepping_mode),
    // {(char*)"stepping_state", T_INT, O(steppingState), READONLY},
    ZUC_STAT_GETSET_DEF(stepping_state),
    // {(char*)"interp_state", T_INT, O(task.interpState), READONLY},
    ZUC_STAT_GETSET_DEF(interp_state),
    // {(char*)"call_level", T_INT, O(task.callLevel), READONLY},
    ZUC_STAT_GETSET_DEF(task_call_level),
    // {(char*)"read_line", T_INT, O(task.readLine), READONLY},
    ZUC_STAT_GETSET_DEF(task_read_line),
    // {(char*)"motion_line", T_INT, O(task.motionLine), READONLY},
    ZUC_STAT_GETSET_DEF(task_motion_line),
    // {(char*)"current_line", T_INT, O(task.currentLine), READONLY},
    ZUC_STAT_GETSET_DEF(task_current_line),
    // {(char*)"sleep_line", T_INT, O(task.sleepLine), READONLY},
    ZUC_STAT_GETSET_DEF(task_sleep_line),
    // {(char*)"executing_line", T_INT, O(task.executingLine), READONLY},
    ZUC_STAT_GETSET_DEF(task_executing_line),
    // {(char*)"err_add_line", T_INT, O(task.errAddLine), READONLY},
    ZUC_STAT_GETSET_DEF(task_err_add_line),
    // {(char*)"file", T_STRING_INPLACE, O(task.file), READONLY},
    ZUC_STAT_GETSET_DEF(file),
    // {(char*)"command", T_STRING_INPLACE, O(task.command), READONLY},
    ZUC_STAT_GETSET_DEF(task_command),
    // {(char*)"program_units", T_INT, O(task.programUnits), READONLY},
    ZUC_STAT_GETSET_DEF(task_program_units),
    // {(char*)"interpreter_errcode", T_INT, O(task.interpreter_errcode), READONLY},
    ZUC_STAT_GETSET_DEF(task_interp_errcode),
    // {(char*)"optional_stop", T_BOOL, O(task.optional_stop_state), READONLY},
    ZUC_STAT_GETSET_DEF(task_optional_stop_state),
    // {(char*)"block_delete", T_BOOL, O(task.block_delete_state), READONLY},
    ZUC_STAT_GETSET_DEF(task_block_del_state),
    // {(char*)"task_paused", T_INT, O(task.task_paused), READONLY},
    ZUC_STAT_GETSET_DEF(task_paused),
    // {(char*)"input_timeout", T_BOOL, O(task.input_timeout), READONLY},
    ZUC_STAT_GETSET_DEF(task_input_timeout),
    // {(char*)"delay_left", T_DOUBLE, O(task.delayLeft), READONLY},
    ZUC_STAT_GETSET_DEF(task_delay_left),
    // {(char*)"queued_mdi_commands", T_INT, O(task.queuedMDIcommands), READONLY, (char*)"Number of MDI commands queued waiting to run."},
    ZUC_STAT_GETSET_DEF(task_queued_MDI_commands),
    // {(char*)"is_diag_collecting", T_BOOL, O(isDiagCollecting), READONLY},
    ZUC_STAT_GETSET_DEF(is_diag_collecting),

    // motion
    // ZUC_TRAJ_STAT traj
    // {(char*)"linear_units", T_DOUBLE, O(motion.traj.linearUnits), READONLY},
    ZUC_STAT_GETSET_DEF(traj_linear_units),
    // {(char*)"angular_units", T_DOUBLE, O(motion.traj.angularUnits), READONLY},
    ZUC_STAT_GETSET_DEF(traj_angular_units),
    // {(char*)"cycle_time", T_DOUBLE, O(motion.traj.cycleTime), READONLY},
    ZUC_STAT_GETSET_DEF(traj_cycle_time),
    // {(char*)"joints", T_INT, O(motion.traj.joints), READONLY},
    ZUC_STAT_GETSET_DEF(traj_joints),
    // {(char*)"axis_mask", T_INT, O(motion.traj.axis_mask), READONLY},
    ZUC_STAT_GETSET_DEF(traj_axis_mask),
    // {(char*)"motion_mode", T_INT, O(motion.traj.mode), READONLY, (char*)"Current mode of MC: TRAJ_MODE_FREE, TRAJ_MODE_COORD, or TRAJ_MODE_TELEOP."},
    ZUC_STAT_GETSET_DEF(motion_mode),
    // {(char*)"inpos", T_BOOL, O(motion.traj.inpos), READONLY},
    ZUC_STAT_GETSET_DEF(inpos),
    // {(char*)"queue", T_INT, O(motion.traj.queue), READONLY},
    ZUC_STAT_GETSET_DEF(traj_queue),
    // {(char*)"active_queue", T_INT, O(motion.traj.activeQueue), READONLY},
    ZUC_STAT_GETSET_DEF(traj_active_queue),
    // {(char*)"queue_full", T_BOOL, O(motion.traj.queueFull), READONLY},
    ZUC_STAT_GETSET_DEF(traj_queue_full),
    // {(char*)"id", T_INT, O(motion.traj.id), READONLY},
    ZUC_STAT_GETSET_DEF(traj_id),
    // {(char*)"paused", T_BOOL, O(motion.traj.paused), READONLY},
    ZUC_STAT_GETSET_DEF(traj_paused),
    // {(char*)"feedrate", T_DOUBLE, O(motion.traj.scale), READONLY},
    ZUC_STAT_GETSET_DEF(traj_feedrate),
    // {(char*)"rapidrate", T_DOUBLE, O(motion.traj.rapid_scale), READONLY},
    ZUC_STAT_GETSET_DEF(traj_rapidrate),

    // {(char*)"velocity", T_DOUBLE, O(motion.traj.velocity), READONLY},
    ZUC_STAT_GETSET_DEF(traj_velocity),
    // {(char*)"acceleration", T_DOUBLE, O(motion.traj.acceleration), READONLY},
    ZUC_STAT_GETSET_DEF(traj_acceleration),
    // {(char*)"max_velocity", T_DOUBLE, O(motion.traj.maxVelocity), READONLY},
    ZUC_STAT_GETSET_DEF(traj_max_velocity),
    // {(char*)"max_acceleration", T_DOUBLE, O(motion.traj.maxAcceleration), READONLY},
    ZUC_STAT_GETSET_DEF(traj_max_acceleration),
    // {(char*)"kinematics_type", T_INT, O(motion.traj.kinematics_type), READONLY},
    ZUC_STAT_GETSET_DEF(traj_kinematics_type),
    // {(char*)"motion_type",
    //  T_INT,
    //  O(motion.traj.motion_type),
    //  READONLY,
    //  (char*)"The type of the currently executing motion (one of MOTION_TYPE_TRAVERSE,\n"
    //         "MOTION_TYPE_FEED, MOTION_TYPE_ARC, MOTION_TYPE_TOOLCHANGE,\n"
    //         "MOTION_TYPE_PROBING, or MOTION_TYPE_INDEXROTARY), or 0 if no motion is\n"
    //         "currently taking place."},
    ZUC_STAT_GETSET_DEF(motion_type),
    // {(char*)"distance_to_go", T_DOUBLE, O(motion.traj.distance_to_go), READONLY},
    ZUC_STAT_GETSET_DEF(distance_to_go),
    // {(char*)"current_vel", T_DOUBLE, O(motion.traj.current_vel), READONLY},
    ZUC_STAT_GETSET_DEF(current_vel),
    // {(char*)"curr_tcp_trans_vel", T_DOUBLE, O(motion.traj.curr_tcp_trans_vel), READONLY},
    ZUC_STAT_GETSET_DEF(curr_tcp_trans_vel),
    // {(char*)"curr_tcp_angular_vel", T_DOUBLE, O(motion.traj.curr_tcp_angular_vel), READONLY},
    ZUC_STAT_GETSET_DEF(curr_tcp_angular_vel),
    // {(char*)"curr_elbow_vel", T_DOUBLE, O(motion.traj.curr_elbow_vel), READONLY},
    ZUC_STAT_GETSET_DEF(curr_elbow_vel),
    // {(char*)"vel_tcp_angular", T_DOUBLE, O(motion.traj.vel_tcp_angular), READONLY},
    ZUC_STAT_GETSET_DEF(vel_tcp_angular),
    // {(char*)"acc_tcp_linear", T_DOUBLE, O(motion.traj.acc_tcp_linear), READONLY},
    ZUC_STAT_GETSET_DEF(acc_tcp_linear),
    // {(char*)"acc_tcp_angular", T_DOUBLE, O(motion.traj.acc_tcp_angular), READONLY},
    ZUC_STAT_GETSET_DEF(acc_tcp_angular),
    // {(char*)"feed_override_enabled", T_BOOL, O(motion.traj.feed_override_enabled), READONLY},
    ZUC_STAT_GETSET_DEF(feed_override_enabled),
    // /*property interface for app clent*/
    // {(char*)"enabled", T_BOOL, O(motion.traj.enabled), READONLY},
    ZUC_STAT_GETSET_DEF(enabled),
    // {(char*)"is_being_enabled", T_BOOL, O(motion.traj.is_being_enabled), READONLY},
    ZUC_STAT_GETSET_DEF(is_being_enabled),
    // {(char*)"cat1StopProgramPaused", T_BOOL, O(motion.category_one_stop_program_pause), READONLY},
    ZUC_STAT_GETSET_DEF(cat1_stop_program_paused),
    // {(char*)"powered_on", T_INT, O(motion.powered_on), READONLY},
    ZUC_STAT_GETSET_DEF(powered_on),
    // {(char*)"is_powering_on", T_BOOL, O(motion.is_powering_on), READONLY},
    ZUC_STAT_GETSET_DEF(is_powering_on),
    // {(char*)"protective_stop", T_INT, O(motion.protective_stop), READONLY},
    ZUC_STAT_GETSET_DEF(protective_stop),
    // {(char*)"emergency_stop", T_INT, O(motion.emergency_stop), READONLY},
    ZUC_STAT_GETSET_DEF(emergency_stop),
    // {(char*)"on_soft_limit", T_INT, O(motion.on_soft_limit), READONLY},
    ZUC_STAT_GETSET_DEF(on_soft_limit),
    // {(char*)"next_to_limit", T_INT, O(motion.next_to_limit), READONLY},
    ZUC_STAT_GETSET_DEF(next_to_limit),
    // {(char*)"percentage_mode_level", T_INT, O(motion.percentage_mode_level), READONLY},
    ZUC_STAT_GETSET_DEF(percentage_mode_level),
    // {(char*)"reduce_mode", T_INT, O(motion.is_reduce_mode), READONLY},
    ZUC_STAT_GETSET_DEF(reduce_mode),
    // {(char*)"next_to_limit", T_INT, O(motion.next_to_limit), READONLY},
    // ZUC_STAT_GETSET_DEF(next_to_limit),
    // {(char*)"servo_upGrade_percentage_total", T_INT, O(motion.servo_upGrade_percentage_total), READONLY},
    ZUC_STAT_GETSET_DEF(servo_upGrade_percentage_total),
    // {(char*)"servo_upGrade_percentage_axis", T_INT, O(motion.servo_upGrade_percentage_axis), READONLY},
    ZUC_STAT_GETSET_DEF(servo_upGrade_percentage_axis),
    // {(char*)"servo_version", T_INT, O(motion.servo.servo_version), READONLY},
    ZUC_STAT_GETSET_DEF(servo_version),
    // {(char*)"first_poweron_date", T_INT, O(motion.servo.first_poweron_date), READONLY},
    ZUC_STAT_GETSET_DEF(first_poweron_date),
    // {(char*)"clsn_sensitivity", T_INT, O(motion.servo.clsn_sensitivity), READONLY},
    ZUC_STAT_GETSET_DEF(clsn_sensitivity),
    // {(char*)"scb_br_start_vol", T_INT, O(motion.scb_br_start_vol), READONLY},
    ZUC_STAT_GETSET_DEF(scb_br_start_vol),
    // {(char*)"robot_serial_num", T_INT, O(motion.robot_serial_num), READONLY},
    ZUC_STAT_GETSET_DEF(robot_serial_num),
    // {(char*)"debug", T_INT, O(debug), READONLY},
    ZUC_STAT_GETSET_DEF(debug),
    // {(char*)"stepping_wait", T_INT, O(steppingWait), READONLY},
    ZUC_STAT_GETSET_DEF(stepping_wait),
    // {(char*)"cab_type", T_INT, O(cab_type), READONLY},
    ZUC_STAT_GETSET_DEF(cab_type),
    // {(char*)"curCabVoltage", T_INT, O(motion.curCabVoltage), READONLY},
    ZUC_STAT_GETSET_DEF(cur_cab_voltage),
    // {(char*)"safetyCRC", T_UINT, O(motion.safetyCRC), READONLY},
    ZUC_STAT_GETSET_DEF(safety_crc),
    // {(char*)"homeVel", T_DOUBLE, O(homeVel), READONLY},
    ZUC_STAT_GETSET_DEF(home_vel),
    // {(char*)"sim_mode", T_INT, O(currSimMode), READONLY},
    ZUC_STAT_GETSET_DEF(sim_mode),
    // {(char*)"tio_lamp_color", T_BYTE, O(tio[0].Lamp_color), READONLY},
    ZUC_STAT_GETSET_DEF(tio_lamp_color),
    // {(char*)"robot_real_power", T_DOUBLE, O(motion.robot_real_power), READONLY},
    ZUC_STAT_GETSET_DEF(robot_real_power),
    // {(char*)"robot_real_momentum", T_DOUBLE, O(motion.robot_real_momentum), READONLY},
    ZUC_STAT_GETSET_DEF(robot_real_momentum),
    //{(char*)"torque_control_enable", T_INT, O(motion.torque_control_enable), READONLY},
    ZUC_STAT_GETSET_DEF(torque_control_enable),
    ZUC_STAT_GETSET_DEF(gravity_direction),
    ZUC_STAT_GETSET_DEF(servo_move_enabled),
    ZUC_STAT_GETSET_DEF(full_dh_flag),
    ZUC_STAT_GETSET_DEF(robot_joint_position),
    ZUC_STAT_GETSET_DEF(robot_tcp_position),
    ZUC_STAT_GETSET_DEF(robot_joint_actual_position),
    ZUC_STAT_GETSET_DEF(robot_dh_param),
    ZUC_STAT_GETSET_DEF(robot_joint_torque),
    {NULL}};

// 定义类构造函数
static int Stat_init(PyStatChannel* self, PyObject* a, PyObject* k)
{
    const char* file = ZUC_DEFAULT_NMLFILE;
    RCS_STAT_CHANNEL* c = new RCS_STAT_CHANNEL(zucFormat, "zucStatus", "xzuc", file);
    if (!c)
    {
        // TODO: err print
        printf("new RCS_STAT_CHANNEL failed");
        return -1;
    }
    self->c = c;
    memset(&self->status, 0, sizeof(self->status));
    self->robstat[0] = NULL;
    self->robstat[1] = NULL;

    //创建robotstat对象
    extern PyTypeObject PyRobotStat_Type;
    auto rob_obj1 = (PyRobotStat*)PyObject_CallObject((PyObject*)&PyRobotStat_Type, NULL);
    if (!rob_obj1)
    {
        printf("rob1\n");
        return -1;  // 创建失败时返回错误
    }
    rob_obj1->motion = &self->status.ext_motion[0];
    Py_INCREF(rob_obj1);
    self->robstat[0] = (PyObject*)rob_obj1;

    PyRobotStat* rob_obj2 = (PyRobotStat*)PyObject_CallObject((PyObject*)&PyRobotStat_Type, NULL);
    if (!rob_obj2)
    {
        Py_DECREF(rob_obj1);
        printf("rob2\n");
        return -1;  // 创建失败时返回错误
    }
    rob_obj2->motion = &self->status.ext_motion[1];
    Py_INCREF(rob_obj2);
    self->robstat[1] = (PyObject*)rob_obj2;
    return 0;
}

// 定义Python的Stat类型，定义析构函数，成员变量等等
static PyTypeObject Stat_Type = {
    .ob_base = PyVarObject_HEAD_INIT(NULL, 0).tp_name = "jkzuc.stat",
    .tp_basicsize = sizeof(PyStatChannel),
    /* methods */
    .tp_dealloc = (destructor)Stat_dealloc,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_methods = Stat_methods,
    .tp_getset = Stat_getsetlist,
    .tp_init = (initproc)Stat_init,
    .tp_new = PyType_GenericNew,
};

int32_t Stat_Ready()
{
    extern PyTypeObject PyRobotStat_Type;
    if (PyType_Ready(&PyRobotStat_Type) < 0)
    {
        return -1;
    }
    return PyType_Ready(&Stat_Type);
}

PyObject* Stat_CreateObject()
{
    PyObject* stat = (PyObject*)&Stat_Type;
    Py_XINCREF(stat);
    return stat;
}

int32_t Stat_DestroyObject(PyObject* stat)
{
    Py_XDECREF((PyObject*)&Stat_Type);
    return 0;
}
